Recibo una advertencia de que BaseException.message está en desuso en Python 2.6 cuando uso la siguiente excepción definida por el usuario:

class MyException(Exception):

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

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

Esta es la advertencia:

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

¿Qué tiene de malo esto? ¿Qué debo cambiar para deshacerme de la advertencia de desaprobación?

180
desolat 13 ago. 2009 a las 17:59

8 respuestas

La mejor respuesta

Solución: casi no se necesita codificación

Simplemente herede su clase de excepción de Exception y pase el mensaje como el primer parámetro al constructor

Ejemplo:

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

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

Puede usar str(my) o (menos elegante) my.args[0] para acceder al mensaje personalizado.

Fondo

En las versiones más recientes de Python (de 2.6) se supone que heredemos nuestras clases de excepción personalizadas de Exception que (a partir de Python 2.5) hereda de BaseException. El fondo se describe en detalle en 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__ y __repr__ ya están implementados de manera significativa, especialmente para el caso de un solo argumento (que puede usarse como mensaje).

No necesita repetir la implementación __str__ o __init__ o crear _get_message como lo sugieren otros.

157
Community 20 jun. 2020 a las 09:12

La publicación de pzrq dice usar:

str(e)

Esto era exactamente lo que necesitaba.

(Si se encuentra en un entorno Unicode, parece que:

unicode(e)

Funcionará, y parece funcionar bien en un entorno no Unicode)

Pzrq dijo muchas otras cosas buenas, pero casi me pierdo su respuesta debido a todas las cosas buenas. Como no tengo 50 puntos, no puedo comentar su respuesta para intentar llamar la atención sobre la solución simple que funciona, y como no tengo 15, no puedo votar esa respuesta, pero puedo publicar (se siente al revés, pero oh bueno), así que aquí estoy publicando, probablemente pierda puntos por eso ...

Dado que mi punto es llamar la atención sobre la respuesta de pzrq, por favor, no te deslumbres y te lo pierdas en todo lo que sigue. Las primeras líneas de esta publicación son las más importantes.

Mi historia:

El problema por el que vine aquí fue si quieres atrapar una excepción de una clase sobre la que no tienes control, ¿entonces qué? ¡Ciertamente no voy a subclasificar todas las clases posibles que usa mi código en un intento de poder obtener un mensaje de todas las posibles excepciones!

Estaba usando:

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

Que, como todos sabemos, da la advertencia sobre la que OP preguntó (que me trajo aquí), y esto, que pzrq da como una forma de hacerlo:

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

No.

No estoy en un entorno Unicode, pero la respuesta de jjc me hizo preguntarme, así que tuve que intentarlo. En este contexto esto se convierte en:

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

Que, para mi sorpresa, funcionó exactamente como str (e), así que ahora eso es lo que estoy usando.

No sé si 'str (e) / unicode (e)' es la 'forma aprobada de Python', y probablemente descubriré por qué eso no es bueno cuando llegue a 3.0, pero uno espera que la capacidad de manejar un excepción inesperada (*) sin morir y aún así obtener información de ella nunca desaparecerá ...

(*) Hmm. "excepción inesperada" - ¡Creo que simplemente tartamudeé!

1
rustycar 7 dic. 2015 a las 16:14

El consejo de usar str (myexception) conduce a problemas Unicode en Python 2.7, por ejemplo:

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

Funciona como se esperaba y se prefiere en los casos en que parte del contenido de la cadena de error incluye la entrada del usuario

1
jjc 7 abr. 2015 a las 23:14

Continuando desde respuesta de geekQ, el reemplazo del código preferido depende de lo que necesite hacer:

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

A veces, las excepciones tienen más de un argumento, por lo que my.args[0] no tiene la garantía de proporcionar toda la información relevante.

Por ejemplo:

# 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 como salida:

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)

Sin embargo, es una compensación sensible al contexto, porque, por ejemplo:

# Python 2.7
>>> str(SyntaxError())
'None'
# 'None' compares True which might not be expected
4
pzrq 3 jul. 2017 a las 14:43

Por lo que puedo decir, el simple uso de un nombre diferente para el atributo del mensaje evita el conflicto con la clase base y, por lo tanto, detiene la advertencia de desaprobación:

class MyException(Exception):

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

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

Me parece un truco.

Tal vez alguien pueda explicar por qué se emite la advertencia incluso cuando la subclase define un atributo de mensaje explícitamente. Si la clase base ya no tiene este atributo, no debería haber ningún problema.

4
Hollister 13 oct. 2010 a las 23:00

Cómo replicar la advertencia

Permítanme aclarar el problema, ya que uno no puede replicar esto con el código de muestra de la pregunta, esto replicará la advertencia en Python 2.6 y 2.7, si tiene las advertencias activadas (a través de -W flag, la PYTHONWARNINGS variable de entorno, o la módulo de advertencias):

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

Dejar de usar .message

Prefiero repr(error), que devuelve una cadena que contiene el nombre del tipo de error, la repr del mensaje, si hay uno, y la repr de los argumentos restantes.

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

Eliminando la advertencia mientras sigue usando .message

Y la forma de obtener deshacerse de la DeprecationWarning es subclasificar una excepción integrada como pretendían los diseñadores de 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',)"

Obteniendo solo el atributo .message sin error.message

Si sabe que hubo un argumento, un mensaje, para la Excepción y eso es lo que desea, es preferible evitar el atributo del mensaje y simplemente tomar el str del error. Digamos para una subclase Exception:

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

Y uso:

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

Ver también esta respuesta:

¿Forma correcta de declarar excepciones personalizadas en Python moderno?

8
Aaron Hall 28 jun. 2019 a las 18:17
class MyException(Exception):

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

e = MyException('asdf')
print e

Esta es tu clase en estilo Python2.6. La nueva excepción toma un número arbitrario de argumentos.

9
Maxim Sloyko 13 ago. 2009 a las 14:09

Sí, está en desuso en Python 2.6 porque desaparecerá en Python 3.0

La clase BaseException ya no proporciona una forma de almacenar mensajes de error. Tendrás que implementarlo tú mismo. Puede hacer esto con una subclase que usa una propiedad para almacenar el mensaje.

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

Espero que esto ayude

25
PaulMcG 15 may. 2010 a las 22:37