183

当我使用以下用户定义的异常时,我收到一条警告说 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

这有什么问题?为了摆脱弃用警告,我必须进行哪些更改?

4

8 回答 8

160

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

只需继承您的异常类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

于 2011-05-17T10:58:34.530 回答
25

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

希望这可以帮助

于 2009-08-13T14:06:51.987 回答
10

如何复制警告

让我澄清一下这个问题,因为不能用问题的示例代码复制它,如果您打开了警告(通过-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',)"

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

如果您知道 Exception 有一个参数,一条消息,而这正是您想要的,那么最好避免使用 message 属性,而只采用str错误的。说一个子类Exception

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

和用法:

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

另请参阅此答案:

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

于 2015-01-29T23:06:04.337 回答
9
class MyException(Exception):

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

e = MyException('asdf')
print e

这是你的 Python2.6 风格的课程。新异常采用任意数量的参数。

于 2009-08-13T14:09:43.017 回答
4

据我所知,简单地为消息属性使用不同的名称可以避免与基类发生冲突,从而停止弃用警告:

class MyException(Exception):

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

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

对我来说似乎是一个黑客。

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

于 2010-10-13T23:00:36.227 回答
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
于 2015-06-17T02:32:20.650 回答
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'δσφφδσ')) 

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

于 2015-04-07T23:14:44.593 回答
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)' 是否是 'approved Python way',当我到 3.0 时我可能会发现为什么这不好,但希望能够处理意外的异常 (*) 没有死亡,仍然从中获得一些信息,永远不会消失......

(*) 唔。“意外异常” - 我想我只是结结巴巴!

于 2015-12-07T15:47:57.623 回答