简体   繁体   English

Python异常的最佳实践?

[英]Best Practices for Python Exceptions?

What are the best practices for creating exceptions? 创建例外的最佳做法是什么? I just saw this, and I don't know if I should be horrified, or like it. 我刚看到这个,我不知道我是否应该感到恐惧或喜欢它。 I read several times in books that exceptions should never ever hold a string, because strings themselves can throw exceptions. 我在书中多次阅读异常永远不会持有字符串,因为字符串本身可以抛出异常。 Any real truth to this? 这有什么真相吗?

Basically from my understanding from the scripts is that this was done so all the inhouse Python libraries will have a common error message format (something that is desperately needed) so I can understand why putting the error message string is a good idea. 基本上我从脚本的理解是这样做,所以所有内部Python库将有一个共同的错误消息格式(迫切需要的东西)所以我可以理解为什么把错误消息字符串是一个好主意。 (Almost every method throws exceptions due to the utter need for nothing invalid getting through). (几乎每种方法都会抛出异常,因为完全不需要无效的通过)。

The code in question is the following: 有问题的代码如下:

"""
Base Exception, Error
"""
class Error(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return "[ERROR] %s\n" % str(self.message)

    def log(self):
        ret = "%s" % str(self.message)
        if(hasattr(self, "reason")):
            return "".join([ret, "\n==> %s" % str(self.reason)])
        return ret

class PCSException(Error):
    def __init__(self, message, reason = None):
        self.message = message
        self.reason = reason
    def __str__(self):
        ret = "[PCS_ERROR] %s\n" % str(self.message)
        if(self.reason != None):
            ret += "[REASON] %s\n" % str(self.reason)
        return ret

This is just the tip of the iceberg, but can someone give me some insight in what makes this a terrible idea? 这只是冰山一角,但有人可以给我一些洞察力,这是一个什么使这个可怕的想法? Or if there is a much better exception coding process/style. 或者,如果有一个更好的异常编码过程/风格。

Robust exception handling (in Python) - a "best practices for Python exceptions" blog post I wrote a while ago. 强大的异常处理(在Python中) - 我之前写过的“Python异常的最佳实践”博客文章。 You may find it useful. 你可能会发现它很有用。

Some key points from the blog: 博客的一些关键点:

Never use exceptions for flow-control 永远不要使用流量控制的例外

Exceptions exist for exceptional situations: events that are not a part of normal execution. 异常情况存在例外情况:不属于正常执行的事件。

Consider 'find' on a string returning -1 if the pattern isn't found, but indexing beyond the end of a string raises an exception. 如果找不到模式,请考虑返回-1的字符串'find',但索引超出字符串结尾会引发异常。 Not finding the string is normal execution. 找不到字符串是正常执行。

Handle exceptions at the level that knows how to handle them 处理知道如何处理它们的级别的异常

... ...

The best place is that piece of code that can handle the exception. 最好的地方是可以处理异常的那段代码。 For some exceptions, like programming errors (eg IndexError, TypeError, NameError etc.) exceptions are best left to the programmer / user, because "handling" them will just hide real bugs. 对于某些异常,例如编程错误(例如IndexError,TypeError,NameError等),异常最好留给程序员/用户,因为“处理”它们只会隐藏真正的错误。

Always ask "is this the right place to handle this exception?" 总是问“这是处理这个例外的正确位置吗?” and be careful with catching all exceptions. 并注意捕捉所有异常。

Document the exceptions thrown by your code 记录代码抛出的异常

... ...

thinking about which exceptions your code may throw will help you write better, safer and more encapsulated code 考虑代码可能引发的异常将帮助您编写更好,更安全和更封装的代码

I read several times in books that exceptions should never ever hold a string, because strings themselves can throw exceptions. 我在书中多次阅读异常永远不会持有字符串,因为字符串本身可以抛出异常。 Any real truth to this? 这有什么真相吗?

What? 什么?

Please provide a reference or a link to this. 请提供参考或链接。 It's totally untrue. 这完全是不真实的。

Since all objects can throw exceptions, no object could be contained in an exception by that logic. 由于所有对象都可以抛出异常,因此该逻辑不会在异常中包含任何对象。

No, the "no strings" is simply crazy in a Python context. 不,“没有字符串”在Python上下文中简直就是疯了。 Perhaps you read it in a C++ context. 也许您是在C ++上下文中阅读它。


Edit 编辑

Once upon a time (back in the olden days) you could raise a Python exception by name instead of by the actual class. 曾几何时(回到过去),您可以通过名称而不是实际的类来引发Python异常。

raise "SomeNameOfAnExceptionClass"

This is bad. 这是不好的。 But this is not including a string inside an exception. 但这包括异常中的字符串。 This is naming the exception with a string instead of the actual class object. 这是使用字符串而不是实际的类对象来命名异常。 In 2.5, this can still work, but gets a deprecation warning. 在2.5中,这仍然有效,但会收到弃用警告。

Perhaps this is what you read "Do not raise an exception with a string name" 也许这就是你读到的“不要用字符串名称引发异常”

I believe the advice against creating exceptions with a string comes from "Learning Python" (O'Reilly). 我相信反对使用字符串创建异常的建议来自“学习Python”(O'Reilly)。 In a section entitled String Exceptions Are Right Out! 在标题为String Exceptions Are Right Out的部分中! , it points out the (now removed) ability to create an exception directly with an arbitrary string. ,它指出了(现已删除)使用任意字符串直接创建异常的能力。

The code it gives as an example is: 它给出的代码是一个例子:

myexc = "My exception string"
try:
    raise myexc
except myexc:
    print ('caught')

This is on p858 of the Fourth Edition (paperback). 这是第四版的p858(平装本)。

First impression is that it's entirely too much code for an exception. 第一印象是异常的代码太多了。

Formatting exceptions should be done in logger configuration. 格式化异常应在记录器配置中完成。 Same goes for the logging itself. 记录本身也是如此。

It also redefines the standard (and deprecated) message attribute, and doesn't call the superclass constructor. 它还重新定义了标准(和已弃用)消息属性,并且不调用超类构造函数。 (This might or might not break Python 3.0 exception chaining, I haven't tried because I'm running 2.6) (这可能会或可能不会破坏Python 3.0异常链接,我没有尝试过,因为我正在运行2.6)

Most of what the extra code does can be realised using BaseException.args, by logging the following as the "message": 使用BaseException.args可以实现额外代码的大部分功能,将以下内容记录为“消息”:

'\n==> '.join(exception.args)

I'd argue that if something can be done using a common / idiomatic mechanism, it should especially be done so in exception handling. 我认为,如果可以使用通用/惯用机制来完成某些事情,那么在异常处理中尤其应该这样做。 (Exceptions being a mechanism to signal something across application layers.) (例外是应用程序层发出信号的机制。)

Personally, I try to avoid anything beyond 就个人而言,我尽量避免任何事情

class SomeException(Exception): pass

(Disclaimer: answer subjective, possibly by nature of the question.) (免责声明:主观回答,可能是问题的性质。)

class Error(Exception):
    """Base class for other exceptions"""
    pass

class empty_string_error(Error):
    """Raised when the input value is too large"""
    pass
while(1):
    try:
        if("Your Condition"):
            raise empty_string_error
        else:
            print("OUTPUT")
    except empty_string_error:
        print("APT MESSAGE")
        print(" ")
    finally:
        pint("Mandatory code")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM