errors - try and catch exception python
¿Por qué son repetibles las iteraciones? (3)
Me ha picado algo inesperado recientemente. Yo quería hacer algo así:
try :
thing.merge(iterable) # this is an iterable so I add it to the list
except TypeError :
thing.append(iterable) # this is not iterable, so I add it
Bueno, funcionó bien hasta que pasé un objeto heredado de Exception que se suponía que debía agregarse.
Desafortunadamente, una excepción es iterable. El siguiente código no TypeError
ningún TypeError
:
for x in Exception() :
print 1
¿Alguien sabe por qué?
En realidad, todavía no lo entiendo del todo. Veo que iterar una Excepción te da los argumentos originales a la excepción, no estoy seguro de por qué alguien querría eso. La iteración implícita es, creo, una de las pocas trampas en Python que todavía me deja boquiabierto.
NO ES VÁLIDO. Revisa a Brian con el guante.
Ok, acabo de entenderlo
for x in Exception("test") :
print x
....:
....:
test
No te molestes ;-)
De todos modos, es bueno saberlo.
EDITAR: mirando a los comentarios, tengo ganas de agregar algunas explicaciones.
Una excepción contiene un mensaje que ha pasado durante la instanciación:
raise Exception("test")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: test
Es justo decir que el mensaje es lo que define la excepción mejor, por lo que str () la devuelve:
print Exception("test")
test
Ahora, sucede que las Excepciones se convierten implícitamente en una cadena cuando se usan en algo más que un contexto de Excepción.
Entonces cuando lo hago:
for x in Exception("test") :
print x
Estoy iterando sobre la cadena "prueba".
Y cuando lo haga:
for x in Exception() :
print x
Yo repito sobre una cadena vacía. Difícil. Porque cuando se trata de mi problema:
try :
thing.merge(ExceptionLikeObject)
except TypeError :
...
Esto no aumentará nada ya que ExceptionLikeObject se considera como una cadena.
Bien, ahora sabemos el CÓMO, pero aún no el POR QUÉ. ¿Tal vez la excepción incorporada hereda de la cadena incorporada? Porque hasta donde yo sé:
- agregar str no hace que ningún objeto sea iterable.
- Pasé por alto el problema al sobrepasarlo, lo que hizo que se aumentara TypeError.
Ya no es un problema, pero sigue siendo un misterio.
Tenga en cuenta que lo que está sucediendo no está relacionado con ningún tipo de conversión de cadena implícita, etc., sino porque la clase Exception implementa __getitem __ () y la utiliza para devolver los valores en la tupla de args (ex.args). Puedes ver esto por el hecho de que obtienes toda la cadena como tu primer y único elemento en la iteración, en lugar del resultado de carácter por carácter que obtendrías si iteraras sobre la cadena.
Esto también me sorprendió, pero pensando en ello, supongo que es por razones de compatibilidad hacia atrás. Python solía ( pre-1.5 ) carecer de la jerarquía de excepciones de clase actual. En su lugar, se lanzaron cadenas, con (normalmente) un argumento de tupla para cualquier detalle que deba pasarse al bloque de manejo. es decir:
try:
raise "something failed", (42, "some other details")
except "something failed", args:
errCode, msg = args
print "something failed. error code %d: %s" % (errCode, msg)
Parece que se puso este comportamiento para evitar romper el código pre-1.5 esperando una tupla de argumentos, en lugar de un objeto de excepción no iterable. Hay un par de ejemplos de esto con IOError en la sección de rotura fatal del enlace anterior
Las excepciones de cadenas se han deducted por un tiempo, y se van en Python 3. Ahora he comprobado cómo Python 3 maneja objetos de excepción, y parece que ya no son iterables allí:
>>> list(Exception("test"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ''Exception'' object is not iterable
[Editar] Comprobó el comportamiento de python3