在 Python 2.6中不推荐使用 BaseException.message

当我使用以下用户定义的异常时,会得到一个警告,说明 BaseException.message 在 Python 2.6中已被弃用:

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

这有什么问题吗? 我需要改变什么才能去除弃用警告?

92926 次浏览

是的,它在 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)

希望这个能帮上忙

class MyException(Exception):


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


e = MyException('asdf')
print e

这是 Python 2.6风格的类,新的异常接受任意数量的参数。

据我所知,只要为 message 属性使用不同的名称,就可以避免与基类发生冲突,从而停止弃用警告:

class MyException(Exception):


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


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

在我看来像是黑客。

也许有人可以解释为什么在子类显式定义消息属性时发出警告。如果基类不再具有此属性,则应该不会出现问题。

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

只需从 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开始)继承我们的自定义异常类,Exception 继承自 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__已经以一种有意义的方式实现了, 特别是对于只有一个参数(可用作消息)的情况。

您不需要重复 __str____init__实现,或者按照其他人的建议创建 _get_message

如何复制警告

让我澄清一下这个问题,因为我们不能用问题的样例代码复制这个问题,所以如果你打开了警告(通过 -W旗帜PYTHONWARNINGS环境变量或者 警告模组) ,这将复制 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',)"

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

如果您知道 Exception 中有一个参数,一条消息,并且这就是您想要的,那么最好避免消息属性,只使用错误的 str。假设子类 Exception:

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

使用方法:

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

请看这个答案:

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

在 python 2.7中,使用 str (myeption)的建议会导致 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'δσφφδσ'))

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

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

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时,我可能会发现它为什么不好,但人们希望处理意外异常(*)的能力不会消失,同时仍然可以从中获得一些信息永远不会消失..。

(*)嗯,“意想不到的例外”-我想我只是结巴了!