Python 2.6中不推荐使用BaseException.message


176

当我使用以下用户定义的异常时,我收到一条警告:Python 2.6中不推荐使用BaseException.message:

class MyException(Exception):

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return repr(self.message)

这是警告:

DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
self.message = message

这怎么了 我要更改什么以摆脱过时警告?


9
出于以下原因,请参阅PEP 352:python.org/dev/peps/pep-0352/#retracted-ideas
balpha

Answers:


154

解决方案-几乎不需要编码

只是继承您的异常类,Exception并将消息作为第一个参数传递给构造函数

例:

class MyException(Exception):
    """My documentation"""

try:
    raise MyException('my detailed description')
except MyException as my:
    print my # outputs 'my detailed description'

您可以使用str(my)或(不太优雅)my.args[0]来访问自定义消息。

背景

在较新的Python版本(从2.6开始)中,我们应该从Exception(从Python 2.5开始)继承自BaseException的自定义异常类中继承。在PEP 352中详细描述了背景。

class BaseException(object):

    """Superclass representing the base of the exception hierarchy.
    Provides an 'args' attribute that contains all arguments passed
    to the constructor.  Suggested practice, though, is that only a
    single string argument be passed to the constructor."""

__str__并且__repr__已经以有意义的方式实现,尤其是对于仅一个arg(可用作消息)的情况。

您无需重复__str____init__实施或创建_get_message其他人建议的内容。


5
@Matt建议将BaseException更改为Exception
geekQ'7

8
利用str休息如果该异常与一个unicode参数构造:str(MyException(u'\xe5'))提高UnicodeEncodeError。使用unicode代替str也不是万无一失,因为unicode(MyException('\xe5'))会引发UnicodeDecodeError。这是否意味着如果我事先不知道参数是否为stror unicode,则必须使用.args[0]以前使用的位置.message
kasperd 2014年

1
@kasperd几乎与所有Python unicode问题一样,可以使用unicode sandwich解决。
Ryan P

3
@RyanP假定我实际上已经控制了所发生的事情。这是我面对的生活事实。我必须处理来自多个第三方库的异常。其中一些将unicode传递给它们的异常,而另一些传递str。其中一个库甚至拥有自己的类,该类继承自unicode,但具有自己的repr方法,该方法返回unicode而不是规范要求的str。
kasperd 2014年

1
我顺便说一句。用替换.message项目中的所有用法,这对我们.args[0]没有造成任何问题。
kasperd 2014年

26

是的,它在Python 2.6中已弃用,因为它在Python 3.0中已经不存在了

BaseException类不再提供存储错误消息的方法。您必须自己实施。您可以使用一个子类来执行此操作,该子类使用用于存储消息的属性。

class MyException(Exception):
    def _get_message(self): 
        return self._message
    def _set_message(self, message): 
        self._message = message
    message = property(_get_message, _set_message)

希望这可以帮助


1
加薪期间如何初始化消息?他的代码显示了通过调用MyException(“ some message”)设置的消息
eric.frederich 2010年

我的示例中的方法仅用于实现message属性。该属性的使用方式取决于编码器。在这种情况下,OP使用他在代码中发布的initstr方法。
Sahas)

1
如果仅读取另一个变量,请考虑使用公共变量而不是getter / setter。@property当您确实需要封装时,可以随时将其升级为语法。
vdboor

2
@vdboor:他正在@property用来禁用过时警告。
bukzor 2012年

创建除获取和设置值(未经检查且未更改)外不执行任何操作的属性是非Python的且无用的。属性的全部要点是允许人们自由使用公共属性,直到实际需要getter或setter的时候为止。然后,您可以将public属性变成一个属性,而不会破坏任何客户端代码。
Luciano Ramalho

9
class MyException(Exception):

    def __str__(self):
        return repr(self.args[0])

e = MyException('asdf')
print e

这是您使用Python2.6样式的类。新的异常采用任意数量的参数。


1
旧的Exception类也接受任意数量的参数。您可以像执行操作一样完全避免使用message属性,但是如果这样做会破坏现有代码,则可以通过实现自己的message属性来解决问题。
萨哈斯在2009年

8

如何复制警告

让我澄清一下问题,因为您无法使用问题的示例代码来复制此问题,如果您启用了警告(通过-WflagPYTHONWARNINGSenvironment变量或warnings模块),则会在Python 2.6和2.7中复制警告:

>>> error = Exception('foobarbaz')
>>> error.message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foobarbaz'

停止使用 .message

我更喜欢使用repr(error),它返回一个字符串,其中包含错误类型的名称,消息的repr(如果有的话)以及其余参数的repr。

>>> repr(error)
"Exception('foobarbaz',)"

仍在使用时消除警告 .message

你得到的方式干掉DeprecationWarning是继承一个内置的例外,因为Python的设计意图:

class MyException(Exception):

    def __init__(self, message, *args):
        self.message = message
        # delegate the rest of initialization to parent
        super(MyException, self).__init__(message, *args)

>>> myexception = MyException('my message')
>>> myexception.message
'my message'
>>> str(myexception)
'my message'
>>> repr(myexception)
"MyException('my message',)"

只获得.message属性而没有error.message

如果您知道要向Exception发送一个参数,即一条消息,这就是您想要的,那么最好避免使用message属性,而只处理str错误。说一个子类Exception

class MyException(Exception):
    '''demo straight subclass'''

和用法:

>>> myexception = MyException('my message')
>>> str(myexception)
'my message'

另请参阅以下答案:

在现代Python中声明自定义异常的正确方法?


4

据我所知,仅对message属性使用其他名称可以避免与基类发生冲突,从而停止弃用警告:

class MyException(Exception):

def __init__(self, message):
    self.msg = message

def __str__(self):
    return repr(self.msg)

在我看来就像是骇客。

也许有人可以解释为什么即使子类显式定义了message属性,也会发出警告。如果基类不再具有此属性,则应该没有问题。


4

继续从geekQ的答案开始,首选的代码替换取决于您需要执行的操作:

### Problem
class MyException(Exception):
    """My documentation"""

try:
    raise MyException('my detailed description')
except MyException as my:
    ### Solution 1, fails in Python 2.x if MyException contains 🔥
    # with UnicodeEncodeError: 'ascii' codec can't encode characters in position 24-25: ordinal not in range(128)
    print(my)  # outputs 'my detailed description'

### Solution 2
# Works in Python 2.x if exception only has ASCII characters,
# should always work in Python 3.x
str(my)

### Solution 3
# Required in Python 2.x if you need to handle non-ASCII characters,
# such as δσφφδσ (as pointed out by jjc) or emoji 🔥 💕 🎁 💯 🌹
# but does not work in Python 3.x
unicode(my)

有时,异常包含多个参数,因此my.args[0]不能保证提供所有相关信息。

例如:

# Python 2.7
try:
    u'\u12345'.encode('utf-8').encode('utf-8')
except UnicodeDecodeError as e:
    print e.args[0]
    print e.args
    print str(e)

打印为输出:

ascii
('ascii', '\xe1\x88\xb45', 0, 1, 'ordinal not in range(128)')
'ascii' codec can't decode byte 0xe1 in position 0: ordinal not in range(128)

但是,这是上下文相关的折衷,因为例如:

# Python 2.7
>>> str(SyntaxError())
'None'
# 'None' compares True which might not be expected

1
是的,不要想太多。使用str(my)代替my.message
Christian Long

1

使用str(myexception)的建议会导致python 2.7中的unicode问题,例如:

str(Exception(u'δσφφδσ'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

:(

unicode(Exception(u'δσφφδσ')) 

可以按预期工作,并且在错误字符串的某些内容包括用户输入的情况下更可取


1

pzrq的帖子说使用:

str(e)

这正是我所需要的。

(如果您在unicode环境中,则似乎:

unicode(e)

可以正常工作,并且在非Unicode环境中似乎可以正常工作)

Pzrq说了很多其他好东西,但是由于所有好东西,我几乎都错过了他们的答案。由于我没有50分,因此我无法就他们的答案发表评论,以引起人们对有效的简单解决方案的关注;由于我没有15分,因此我无法投票赞成该答案,但是我可以发表评论(感觉是倒退的,但是哦,好)-我在这里发布-可能会因此而失去积分...

由于我的意思是要引起人们对pzrq答案的关注,请不要着迷并在下面的所有内容中忽略它。这篇文章的前几行是最重要的。

我的故事:

我来到这里的问题是,如果您想从无法控制的类中捕获异常,那么该怎么办?我当然不会继承我的代码使用的所有可能的类,以试图从所有可能的异常中获取消息!

我正在使用:

except Exception as e:
   print '%s (%s)' % (e.message,type(e))

正如我们现在所知道的那样,它给出了警告OP的警告(这将我带到了这里),而这就是pzrq给出的一种解决方法:

except Exception as e:
   print '%s (%s)' % (str(e),type(e))

没有。

我不是在unicode环境中,但是jjc的回答让我感到疑惑,因此我不得不尝试一下。在这种情况下,它将变为:

except Exception as e:
   print '%s (%s)' % (unicode(e),type(e))

令我惊讶的是,它的工作原理与str(e)完全一样-所以现在这就是我正在使用的。

不知道'str(e)/ unicode(e)'是否是'认可的Python方式',我很可能会发现为什么当我达到3.0时这不好,但是有人希望能够处理不会死的意外异常(*)永远不会消失...

(*)嗯。“意外异常”-我想我口吃了!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.