PyMOTW: exceptions

21 Septiembre 2008

Traducción de PyMOTW: exceptions, el módulo exceptions de la columna semanal de Doug Hellmann.


Comentarios

Módulo exceptions
Propósito El módulo exceptions define los errores incorporados que se usan en la biblioteca estándar y por el intérprete.
Versión de Python 1.5 y posterior

Descripción

En el pasado, Python ha soportado cadenas simples de mensajes como excepciones así como clases. Desde la versión 1.5, todos los módulos de la biblioteca estándar usan clases para excepciones. A partir de Python 2.5, excepciones de cadenas resultan en una advertencia DeprecationWarning, y el soporte para excepciones de cadenas va a ser retirado en el futuro.

Clases base

Las clases de excepciones están definidas en una jerarquía, que está descrita en la documentación de la biblioteca estándar. Adicionalmente a los beneficios obvios de organización, la herencia de excepciones es útil porque excepciones relacionadas pueden ser atrapadas atrapando su clase base. En la mayoría de los casos, estas clases base no están destinadas a ser lanzadas directamente.

BaseException

Clase base para todas las excepciones. Implementa la lógica para crear una cadena que represente la excepciones usando str() con los argumentos que se pasan al constructor.

Exception

Clase base para excepciones que no resultan en la terminación de la aplicación que se está ejecutando. Todas las excepciones definidas por el usuario deberían usar Exception como clase base.

StandardError

Clase base para excepciones incorporadas usadas en la biblioteca estándar.

ArithmeticError

Clase base para errores matemáticos.

LookupError

Clase base para errores que son lanzados cuando algo no puede ser encontrado.

EnvironmentError

Clase base para errores que vienen de fuera de Python (el sistema operativo, el sistema de archivos, etc.).

Excepciones lanzadas

AssertionError

Un AssertionError es lanzado por una instrucción assert fallida.

assert False, 'La afirmación ha fallado'

$ python exceptions_AssertionError_assert.py
Traceback (most recent call last):
  File "exceptions_AssertionError_assert.py", line 12, in <module>
    assert False, 'La afirmación ha fallado'
AssertionError: La afirmación ha fallado

También es usado en el módulo unittest en métodos como failIf().

import unittest

class AssertionExample(unittest.TestCase):

    def test(self):
        self.failUnless(False)

unittest.main()

$ python exceptions_AssertionError_unittest.py
F
======================================================================
FAIL: test (__main__.AssertionExample)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "exceptions_AssertionError_unittest.py", line 17, in test
    self.failUnless(False)
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

AttributeError

Cuando una referencia o una asignación a un atributo fallan, AttributeError es lanzado.

Por ejemplo, cuando se trata de referencias a una atributo que no existe:

class NoAttributes(object):
    pass

o = NoAttributes()
print o.attribute

$ python exceptions_AttributeError.py
Traceback (most recent call last):
  File "exceptions_AttributeError.py", line 16, in <module>
    print o.attribute
AttributeError: 'NoAttributes' object has no attribute 'attribute'

O cuando se trata de modificar un atributo sólo de lectura.

class MyClass(object):

    @property
    def attribute(self):
        return 'Este es el valor de attribute'

o = MyClass()
print o.attribute
o.attribute = 'Nuevo valor'

$ python exceptions_AttributeError_assignment.py
Este es el valor de attribute
Traceback (most recent call last):
  File "exceptions_AttributeError_assignment.py", line 20, in <module>
    o.attribute = 'Nuevo valor'
AttributeError: can't set attribute

EOFError

Un EOFError es lanzado cuando una función incorporada como input() o raw_input() no lee ningún dato antes de encontrar en final de su flujo de entrada. Los métodos de archivo como read() devuelven una cadena vacía al final del archivo.

while True:
    data = raw_input('prompt:')
    print 'LEIDO:', data

$ echo hello | python exceptions/exceptions_EOFError.py
prompt:LEIDO: hello
prompt:Traceback (most recent call last):
  File "exceptions_EOFError.py", line 13, in <module>
    data = raw_input('prompt:')
EOFError: EOF when reading a line

FloatingPointError

Es lanzada por operaciones con números de coma flotante que resultan en errores, cuando el control de excepción de coma flotante (fpectl, floating point exception control) está activado. Activar fpectl requiere de un intérprete compilado con --with-fpectl. El uso de fpectl no se recomienda en la documentación de la biblioteca estándar http://docs.python.org/lib/module-fpectl.html.

import math
import fpectl

print 'Control desactivado:', math.exp(1000)
fpectl.turnon_sigfpe()
print 'Control activado:', math.exp(1000)

GeneratorExit

Es lanzada dentro de un generador si el método close() del generador es invocado.

def my_generator():
    try:
        for i in range(5):
            print 'Rindiendo', i
            yield i
    except GeneratorExit:
        print 'Saliendo anticipadamente'

g = my_generator()
print g.next()
g.close()

$ python exceptions_GeneratorExit.py
Rindiendo 0
0
Saliendo anticipadamente

IOError

Es lanzada cuando la entrada o salida fallan, por ejemplo si un disco se llena o un archivo de entrada no existe.

f = open('/no/existe', 'r')

$ python exceptions_IOError.py
Traceback (most recent call last):
  File "exceptions_IOError.py", line 12, in <module>
    f = open('/no/existe', 'r')
IOError: [Errno 2] No such file or directory: '/no/existe'

ImportError

Es lanzada cuando un módulo, o un miembro de un módulo no puede ser importado. Hay algunas condiciones en las que ImportError puede ser lanzada.

  1. Si un módulo no existe.

    import module_no_existe

    $ python exceptions_ImportError_nomodule.py Traceback (most recent call last): File "exceptions_ImportError_nomodule.py", line 12, in import module_no_existe ImportError: No module named module_no_existe

  2. Si from X import Y es usado y Y no puede ser encontrado dentro del módulo X, un ImportError es lanzado.

    from exceptions import NombreInventado

    $ python exceptions_ImportError_missingname.py Traceback (most recent call last): File "exceptions_ImportError_missingname.py", line 12, in from exceptions import NombreInventado ImportError: cannot import name NombreInventado

IndexError

Un IndexError es lanzado cuando una referencias en una secuencia está fuera de rango.

my_seq = [ 0, 1, 2 ]
print my_seq[3]

$ python exceptions_IndexError.py
Traceback (most recent call last):
  File "exceptions_IndexError.py", line 13, in <module>
    print my_seq[3]
IndexError: list index out of range

KeyError

De manera similar, un KeyError es lanzado cuando un valor no es encontrado como llave de un diccionario.

d = { 'a':1, 'b':2 }
print d['c']

$ python exceptions_KeyError.py
Traceback (most recent call last):
  File "exceptions_KeyError.py", line 13, in <module>
    print d['c']
KeyError: 'c'

KeyboardInterrupt

Un KeyboardInterrupt ocurre cuando el usuario presiona Control-C (o Delete) para detener un programa en ejecución. A diferencias de la mayoría de las excepciones, KeyboardInterrupt se deriva directamente de BaseException para evitar ser atrapada por gestores de excepción globales que atrapan Exception.

try:
    print 'Presiona Return o Control-C:',
    ignored = raw_input()
except Exception, err:
    print 'Excepción atrapada:', err
except KeyboardInterrupt, err:
    print 'Excepción KeyboardInterrupt'
else:
    print 'Ninguna excepción'

Presionando Control-C en la consola ocasiona una excepción KeyboardInterrupt.

$ python exceptions_KeyboardInterrupt.py
Presiona Return o Control-C: Excepción KeyboardInterrupt

MemoryError

Si tu programa se queda sin memoria y es posible recuperarse (eliminando algunos objetos, por ejemplo), un MemoryError es lanzado.

import itertools

# Intenta crear un MemoryError asignando un montón de memoria
l = []
for i in range(3):
    try:
        for j in itertools.count(1):
            print i, j
            l.append('*' * (2**30))
    except MemoryError:
        print '(error, descartando la lista existente)'
        l = []

$ python exceptions_MemoryError.py
0 1
0 2
(error, descartando la lista existente)
1 1
1 2
(error, descartando la lista existente)
2 1
2 2
(error, descartando la lista existente)

NameError

NameErrors son lanzados cuando tu código hace referencia a un nombre que no existe en el ámbito (scope) actual. Por ejemplo, el nombre de una variable.

def func():
    print nombre_desconocido

func()

$ python exceptions_NameError.py
Traceback (most recent call last):
  File "exceptions_NameError.py", line 15, in <module>
    func()
  File "exceptions_NameError.py", line 13, in func
    print nombre_desconocido
NameError: global name 'nombre_desconocido' is not defined

NotImplementedError

Clases base definidas por el usuario pueden lanzar NotImplementedError para indicar que un método o comportamiento tiene que ser definido por una sub clase, simulado así una interfaz.

class BaseClass(object):
    """Define la interfaz"""
    def __init__(self):
        super(BaseClass, self).__init__()
    def do_something(self):
        """La interfaz, sin implementar"""
        raise NotImplementedError(self.__class__.__name__ + '.do_something')

class SubClass(BaseClass):
    """Implementa la interfaz"""
    def do_something(self):
        """hace algo de verdad"""
        print self.__class__.__name__ + ' doing something!'

SubClass().do_something()
BaseClass().do_something()

$ python exceptions_NotImplementedError.py
SubClass haciendo algo!
Traceback (most recent call last):
  File "exceptions_NotImplementedError.py", line 27, in <module>
    BaseClass().do_something()
  File "exceptions_NotImplementedError.py", line 18, in do_something
    raise NotImplementedError(self.__class__.__name__ + '.do_something')
NotImplementedError: BaseClass.do_something

OSError

OSError sirve como la clase de error para el módulo os, y es lanzado cuando un error surge de una función específica del sistema operativo.

import os

for i in range(10):
    print i, os.ttyname(i)

$ python exceptions_OSError.py
0 /dev/pts/0
1 /dev/pts/0
2 /dev/pts/0
3
Traceback (most recent call last):
  File "exceptions_OSError.py", line 15, in <module>
    print i, os.ttyname(i)
OSError: [Errno 9] Bad file descriptor

OverflowError

Cuando una operación aritmética supera los límites del tipo de variable, un OverflowError es lanzado. Número enteros grandes asignan más espacio a medida que los valores crece, entonces terminan lanzando MemoryError. La gestión de excepciones de números de coma flotante no está estandarizada, entonces los números de coma flotante no se comprueban. Número enteros normales son convertidos a valores long según sea necesario.

import sys

print 'Número entereo normal: (maxint=%s)' % sys.maxint
try:
    i = sys.maxint * 3
    print 'Sin rebalse para ', type(i), 'i =', i
except OverflowError, err:
    print 'Rebalse en ', i, err

print
print 'Número entero largo:'
for i in range(0, 100, 10):
    print '%2d' % i, 2L ** i

print
print 'Valores de coma flotante:'
try:
    f = 2.0**i
    for i in range(100):
        print i, f
        f = f ** 2
except OverflowError, err:
    print 'Rebalse luego de ', f, err

$ python exceptions_OverflowError.py
Número entereo normal: (maxint=2147483647)
Sin rebalse para  <type 'long'> i = 6442450941

Número entero largo:
 0 1
10 1024
20 1048576
30 1073741824
40 1099511627776
50 1125899906842624
60 1152921504606846976
70 1180591620717411303424
80 1208925819614629174706176
90 1237940039285380274899124224

Valores de coma flotante:
0 1.23794003929e+27
1 1.53249554087e+54
2 2.34854258277e+108
3 5.5156522631e+216
Rebalse luego de  5.5156522631e+216 (34, 'Numerical result out of range')

ReferenceError

Cuando un proxy weakref es usado para acceder a un objeto que ya ha sido recolectado (garbage collected), un ReferenceError ocurre.

import gc
import weakref

class ExpensiveObject(object):
    def __init__(self, name):
        self.name = name
    def __del__(self):
        print '(Borrando %s)' % self

obj = ExpensiveObject('obj')
p = weakref.proxy(obj)

print 'ANTES:', p.name
obj = None
print 'DESPUÉS:', p.name

$ python exceptions_ReferenceError.py
ANTES: obj
(Borrando <__main__.ExpensiveObject object at 0xb7d1d64c>)
DESPUÉS:
Traceback (most recent call last):
  File "exceptions_ReferenceError.py", line 26, in <module>
    print 'DESPUÉS:', p.name
ReferenceError: weakly-referenced object no longer exists

RuntimeError

Una excepción RuntimeError es usada cuando ninguna otra excepción más específica es aplicable. El intérprete no lanza esta excepción con mucha frecuencia, pero código de usuario lo hace.

StopIteration

Cuando un iterador ha terminado, su método next() lanza StopIteration. Esta excepción no es considerada un error.

l=[0,1,2]
i=iter(l)

print i
print i.next()
print i.next()
print i.next()
print i.next()

$ python exceptions_StopIteration.py
<listiterator object at 0xb7d6fb2c>
0
1
2
Traceback (most recent call last):
  File "exceptions_StopIteration.py", line 19, in <module>
    print i.next()
StopIteration

SyntaxError

Un SyntaxError ocurre cada vez que el analizador (parser) encuentra código fuente que no entiende. Esto puede ser al importar un módulo, invocando exec, o invocando eval(). Los atributos de la excepción pueden ser usados para encontrar exactamente qué parte del texto de entrada ocasionó la excepción.

try:
    print eval('cinco por tres')
except SyntaxError, err:
    print 'Error de sintaxis %s (%s-%s): %s' % \
        (err.filename, err.lineno, err.offset, err.text)
    print err

$ python exceptions_SyntaxError.py
Error de sintáxis <string> (1-9): cinco por tres
invalid syntax (<string>, line 1)

SystemError

Cuando un error ocurre en el intérprete mismo y hay alguna oportunidad de continuar la ejecución con éxito, lanza un SystemError. SystemErrors probablemente indican una falla (bug) en el intérprete y deberían ser reportados al mantenedor.

SystemExit

Cuando sys.exit() es invocada, lanza SystemExit en lugar de salir inmediatamente. Esto permite ejecutar código de limpieza en bloques try:finally y a los que invocan el código (como depuradores y frameworks de prueba) capturar las excepciones y evitan salir.

TypeError

TypeErrors son ocasionados al combinar tipos equivocados de objetos o invocando una función con el tipo de objeto equivocado.

result = ('tupla',) + 'cadena'

$ python exceptions_TypeError.py
Traceback (most recent call last):
  File "exceptions_TypeError.py", line 12, in <module>
    result = ('tupla',) + 'cadena'
TypeError: can only concatenate tuple (not "str") to tuple

UnboundLocalError

Un UnboundLocalError es un tipo de NameError específico para nombres de variables locales.

def throws_global_name_error():
    print unknown_global_name

def throws_unbound_local():
    local_val = local_val + 1
    print local_val

try:
    throws_global_name_error()
except NameError, err:
    print 'Error de nombre global:', err

try:
    throws_unbound_local()
except UnboundLocalError, err:
    print 'Error de nombre local:', err

La diferencia entre el NameError global y el UnboundLocalError es la manera en que el nombre es usado. Ya que el nombre "local_val" aparece en el lado izquierdo de una expresión, es interpretada como un nombre de variable local.

$ python exceptions_UnboundLocalError.py
Error de nombre global: global name 'unknown_global_name' is not defined
Error de nombre local: local variable 'local_val' referenced before assignment

UnicodeError

UnicodeError es una sub clase de ValueError y es lanzado cuando surge un problema con Unicode. Hay clases sub clases separadas para UnicodeEncodeError, UnicodeDecodeError, y UnicodeTranslateError.

ValueError

Un ValueError es usado cuando una función recibe un valor que tiene el tipo correcto pero un valor inválido.

print chr(1024)

$ python exceptions_ValueError.py
Traceback (most recent call last):
  File "exceptions_ValueError.py", line 12, in <module>
    print chr(1024)
ValueError: chr() arg not in range(256)

ZeroDivisionError

Cuando cero aparece en el denominador de una operación de división, un ZeroDivisionError es lanzado.

print 1/0

$ python exceptions_ZeroDivisionError.py
Traceback (most recent call last):
  File "exceptions_ZeroDivisionError.py", line 12, in <module>
    print 1/0
ZeroDivisionError: integer division or modulo by zero

Categorías de Warning

También hay varias excepciones definidas para ser usadas con el módulo warnings.

Warning
La clase base para todas las advertencias (*warnings*).
UserWarning
Clase base para advertencias que surgen en código del usuario.
DeprecationWarning
Usada para características que ya no están siendo mantenidas.
PendingDeprecationWarning
Usada para características que van a ser obsoletas pronto.
SyntaxWarning
Usada para sintáxis dudosa.
RuntimeWarning
Usada para para eventos que suceden en la ejecución que pueden causar problemas.
FutureWarning
Advertencia sobre cambios al lenguaje o la biblioteca en el futuro.
ImportWarning
Advertencia sobre problemas al importar un módulo.
UnicodeWarning
Advertencia sobre problemas con texto unicode.

Referencias

Documentación biblioteca estándar: exceptions

Copyright 2008 Doug Hellmann


blog comments powered by Disqus

Categorías