Недостаток 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, но надеется, что способность обрабатывать неожиданное исключение (*), не умирая и все равно получать некоторую информацию от него, никогда не исчезнет...

(*) Хмм. "неожиданное исключение" - я думаю, что я просто заикался!