Недостаток BaseException.message в Python 2.6
Я получаю предупреждение о том, что 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
Что случилось с этим? Что мне нужно изменить, чтобы избавиться от предупреждения об устаревании?
Ответы
Ответ 1
Решение - практически не требуется кодирование
Просто наследуйте свой класс исключения от 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__
уже реализованы значимым образом,
особенно для случая только одного аргумента (который может использоваться как сообщение).
Вам не нужно повторять реализацию __str__
или __init__
или создавать _get_message
, как это было предложено другими.
Ответ 2
Да, он устарел в 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)
Надеюсь, что это поможет
Ответ 3
class MyException(Exception):
def __str__(self):
return repr(self.args[0])
e = MyException('asdf')
print e
Это ваш класс в стиле Python2.6. Новое исключение принимает произвольное количество аргументов.
Ответ 4
Как повторить предупреждение
Позвольте мне прояснить проблему, так как нельзя повторить это с примером кода вопроса, это будет повторять предупреждение в Python 2.6 и 2.7, если у вас включены предупреждения (через флаг -W
, PYTHONWARNINGS
среды PYTHONWARNINGS
или предупреждения модуль):
>>> 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
Если вы знаете, что был один аргумент, сообщение, для исключения и того, что вы хотите, предпочтительно избегать атрибута сообщения и просто принимать str
ошибки. Скажем для Exception
в подклассе:
class MyException(Exception):
'''demo straight subclass'''
И использование:
>>> myexception = MyException('my message')
>>> str(myexception)
'my message'
Смотрите также этот ответ:
Правильный способ объявить пользовательские исключения в современном Python?
Ответ 5
Насколько я могу судить, просто используя другое имя для атрибута сообщения избегает конфликта с базовым классом и тем самым останавливает предупреждение об отказе:
class MyException(Exception):
def __init__(self, message):
self.msg = message
def __str__(self):
return repr(self.msg)
Кажется, мне нравится.
Возможно, кто-то может объяснить, почему предупреждение выдается, даже если подкласс определяет атрибут сообщения явно. Если базовый класс больше не имеет этого атрибута, не должно быть проблем.
Ответ 6
Продолжая с ответ 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
Ответ 7
Совет по использованию str (myexception) приводит к проблемам с unicode в python 2.7, например:
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'δσφφδσ'))
работает так, как ожидалось, и предпочтителен в тех случаях, когда часть содержимого строки ошибки включает пользовательский ввод
Ответ 8
pzrq post говорит, чтобы использовать:
str(e)
Это именно то, что мне нужно.
(Если вы находитесь в среде unicode, то появляется следующее:
unicode(e)
будет работать, и, похоже, он отлично работает в среде, отличной от юникода)
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, но надеется, что способность обрабатывать неожиданное исключение (*), не умирая и все равно получать некоторую информацию от него, никогда не исчезнет...
(*) Хмм. "неожиданное исключение" - я думаю, что я просто заикался!