web-dev-qa-db-fra.com

BaseException.message obsolète dans Python 2.6

Je reçois un avertissement que BaseException.message est obsolète dans Python 2.6 lorsque j'utilise l'exception suivante définie par l'utilisateur:

class MyException(Exception):

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

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

C'est l'avertissement:

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

Quel est le problème avec cela? Que dois-je changer pour me débarrasser de l'avertissement de dépréciation?

162
desolat

Solution - presque aucun codage nécessaire

Héritez simplement votre classe d'exception de Exception et transmettez le message en tant que premier paramètre au constructeur

Exemple:

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

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

Vous pouvez utiliser str(my) ou (moins élégant) my.args[0] Pour accéder au message personnalisé.

Contexte

Dans les versions plus récentes de Python (à partir de la version 2.6), nous sommes supposés hériter de nos classes d'exception personnalisées d'Exception qui ( à partir de Python 2.5 ) hérite de BaseException. L’arrière-plan est décrit en détail dans 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__ Et __repr__ Sont déjà implémentés de manière significative, en particulier dans le cas d'un seul argument (pouvant être utilisé comme message).

Vous n'avez pas besoin de répéter l'implémentation __str__ Ou __init__ Ni de créer _get_message Comme suggéré par d'autres.

144
geekQ

Oui, il est déconseillé dans Python 2.6 car il disparaît dans Python 3.0

La classe BaseException ne fournit plus un moyen de stocker un message d'erreur. Vous devrez l'implémenter vous-même. Vous pouvez le faire avec une sous-classe qui utilise une propriété pour stocker le message.

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

J'espère que cela t'aides

25
Sahas
class MyException(Exception):

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

e = MyException('asdf')
print e

Ceci est votre classe dans le style Python2.6. La nouvelle exception prend un nombre arbitraire d'arguments.

9
Maxim Sloyko

Comment répliquer l'avertissement

Permettez-moi de clarifier le problème, car on ne peut pas reproduire cela avec l'exemple de code de la question, cela répliquera l'avertissement dans Python 2.6 et 2.7, si vous avez activé des avertissements (via le Indicateur -W , la variable d'environnement PYTHONWARNINGS , ou module d'avertissements ):

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

Arrêtez d'utiliser .message

Je préfère repr(error), qui renvoie une chaîne contenant le nom du type d'erreur, le repr du message, s'il en existe un, et le repr des arguments restants.

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

Éliminer l'avertissement tout en utilisant encore .message

Et la façon dont vous obtenez débarrassez du DeprecationWarning consiste à sous-classer une exception intégrée comme le Python les concepteurs ont prévu:

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',)"

obtenir uniquement l'attribut .message sans error.message

Si vous savez qu'il y a eu un argument, un message, à l'exception et que c'est ce que vous voulez, il est préférable d'éviter l'attribut de message et de simplement prendre le str de l'erreur. Dites pour un sous-groupe Exception:

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

Et utilisation:

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

Voir aussi cette réponse:

Moyen approprié de déclarer des exceptions personnalisées dans Python moderne?

6
Aaron Hall

En continuant à partir de réponse de geekQ , le remplacement de code préféré dépend de ce que vous devez faire:

### 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)

Parfois, les exceptions ont plus d'un argument, alors my.args[0] n'est pas garanti de fournir toutes les informations pertinentes.

Par exemple:

# 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)

Imprime en sortie:

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)

Cependant, c'est un compromis sensible au contexte, parce que, par exemple:

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

Autant que je sache, le simple fait d'utiliser un nom différent pour l'attribut de message évite le conflit avec la classe de base et arrête ainsi l'avertissement de dépréciation:

class MyException(Exception):

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

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

On dirait un bidouillage pour moi.

Quelqu'un peut peut-être expliquer pourquoi l'avertissement est émis même lorsque la sous-classe définit explicitement un attribut de message. Si la classe de base n'a plus cet attribut, il ne devrait pas y avoir de problème.

3
Hollister

le message de pzrq dit d'utiliser:

str(e)

C'était exactement ce dont j'avais besoin.

(Si vous êtes dans un environnement unicode, il apparaît que:

unicode(e)

fonctionnera, et il semble fonctionner correctement dans un environnement non-unicode)

Pzrq a dit beaucoup d'autres choses intéressantes, mais j'ai failli rater leur réponse à cause de toutes les bonnes choses. Comme je n’ai pas 50 points, je ne peux pas commenter leur réponse pour tenter d’attirer l’attention sur la solution simple qui fonctionne, et comme je n’en ai pas 15, je ne peux pas voter pour cette réponse, mais je peux poster (me sens en arrière, mais oh bien) - alors je poste ici - probablement perdre des points pour cela ...

Puisque mon but est d'attirer l'attention sur la réponse de pzrq, s'il vous plaît, ne glissez pas dessus et ne la manquez pas dans tout ce qui suit. les premières lignes de ce post sont les plus importantes.

Mon histoire:

Le problème pour lequel je suis venu ici était si vous voulez capturer une exception d'une classe sur laquelle vous n'avez aucun contrôle - alors? Je ne vais certainement pas sous-classer toutes les classes possibles utilisées par mon code pour pouvoir extraire un message de toutes les exceptions possibles!

J'utilisais:

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

qui, comme nous le savons tous à présent, donne l’avertissement à propos de l’op question posée (ce qui m’a amené ici), et c’est ce que pzrq donne comme moyen de le faire:

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

n'a pas.

Je ne suis pas dans un environnement unicode, mais la réponse de jjc m'a fait me demander, alors j'ai dû l'essayer. Dans ce contexte, cela devient:

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

qui, à ma grande surprise, fonctionnait exactement comme str (e) - c’est ce que j’utilise.

Je ne sais pas si "str (e)/unicode (e)" est la "manière approuvée Python"), et je vais probablement découvrir pourquoi ce n'est pas bon quand j'arrive à la version 3.0, mais on espère que la capacité à gérer une exception inattendue (*) sans mourir et à en tirer quelques informations ne disparaîtra jamais ...

(*) Hmm. "exception inattendue" - Je pense que je viens de bégayer!

1
rustycar

Le conseil d’utiliser str (myexception) conduit à des problèmes unicode dans python 2.7, par exemple:

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'δσφφδσ')) 

fonctionne comme prévu et est préférable dans les cas où une partie du contenu de la chaîne d'erreur inclut une entrée utilisateur

1
jjc