que - qué son las tuplas en python
¿Por qué criar una tupla funciona si el primer elemento es una excepción? (3)
Al parecer, Python también acepta una tupla no vacía para la primera expresión en una declaración de aumento a pesar de la documentación (pero como se indica en http://www.python.org/dev/peps/pep-3109/#id17 ), y si es una tupla, utiliza recursivamente su primer elemento para la clase de la excepción. Déjame mostrarte un código:
>>> raise ValueError, ''sdf'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: sdf
>>> raise (ValueError, 5), ''sdf'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: sdf
A pesar de lo que dije en mi comentario anterior, no hay desempaquetado automático, porque la cadena no se pasa a la clase de excepción en mi siguiente ejemplo:
>>> raise (ValueError, ''sdf'', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError
También utilizando el módulo ast de python, podemos ver que en una expresión de subida no hay una tupla por defecto:
>>> ast.dump(ast.parse(''raise ValueError, "asd"''))
"Module(body=[Raise(type=Name(id=''ValueError'', ctx=Load()), inst=Str(s=''asd''), tback=None)])"
Y si usamos una tupla, se pasa como el argumento de tipo:
>>> ast.dump(ast.parse(''raise (ValueError, "asd")''))
"Module(body=[Raise(type=Tuple(elts=[Name(id=''ValueError'', ctx=Load()), Str(s=''asd'')], ctx=Load()), inst=None, tback=None)])"
Me cuesta entender esto, se trata de errores que se pueden hacer al generar una excepción en Python 2.7:
try:
raise [1, 2, 3, 4]
except Exception as ex:
print ex
el mensaje aquí es "las excepciones deben ser de estilo antiguo o derivadas de BaseException, no de la lista": esta parte está bien, pero cuando la cambio a tupla, me estoy confundiendo:
try:
raise (1, 2, 3, 4)
except Exception as ex:
print ex
el mensaje aquí es "las excepciones deben ser clases de estilo antiguo o derivadas de BaseException, no int". ¿Por qué se interpreta como elevar un int, no una tupla?
Más lejos
try:
raise (Exception, ''a message'')
except Exception as ex:
print ex
Aquí en realidad estamos aumentando una Excepción (comportamiento consistente en comparación con el ejemplo anterior, en el que elevábamos un int). Pensé brevemente que esto es solo una forma alternativa para esto:
try:
raise Exception, ''a message''
except Exception as ex:
print ex
Pero en este caso, se está pasando ''un mensaje'' al ctor de excepciones (como se documenta en docs.python.org)
¿Puede alguien explicar los casos segundo y tercero, y posiblemente señalarme el código del intérprete responsable de esto?
Tal como se documenta en la referencia de python , la instrucción raise
toma hasta 3 expresiones para crear la excepción que se plantea:
raise_stmt :: = "raise" [expresión ["," expresión ["," expresión]]]
En Python 2, si la primera expresión es una tupla, python "desenvolverá" la tupla de forma recursiva, tomando el primer elemento hasta que encuentre algo que no sea una tupla. Este comportamiento se está eliminando de Python 3 (ver PEP 3109. Lo siguiente es legal:
>>> raise ((Exception, ''ignored''), ''ignored''), ''something'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: something
La documentación explica el resto con más detalle, pero la declaración de aumento espera que el primer valor sea una clase de Excepción, el segundo valor se ve como el valor de la excepción (el mensaje) y el tercer valor es un rastreo. Python completa None
para los dos últimos valores, si faltan.
Si el primer valor es una instancia , el segundo valor debe ser Ninguno:
>>> raise Exception(''something''), ''something'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: instance exception may not have a separate value
Si usa una tupla de más de 3 elementos, se generará un error de sintaxis:
>>> raise Exception, ''something'', None, None
File "<stdin>", line 1
raise Exception, ''something'', None, None
^
SyntaxError: invalid syntax
Sin embargo, en su caso, no generó una clase ni una instancia, así que eso es lo que Python encontró incorrecto primero; Si uso una cuerda, también se quejará:
>>> raise ''not an exception'', ''something'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exceptions must be old-style classes or derived from BaseException, not str
La sintaxis correcta es, por supuesto:
>>> raise Exception, ''something'', None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: something
http://docs.python.org/reference/simple_stmts.html#the-raise-statement
"elevar" [expresión ["," expresión ["," expresión]]]
Si no hay expresiones presentes, raise re-raises la última excepción que estaba activa en el alcance actual ... De lo contrario, raise evalúa las expresiones para obtener tres objetos , utilizando None como el valor de las expresiones omitidas. Los primeros dos objetos se utilizan para determinar el tipo y el valor de la excepción.
En realidad, pensé que Python hace el desempaquetado de tuple aquí
try:
raise (ValueError, "foo", ), "bar"
except Exception as e:
print e.message # foo or bar?
pero si lo hiciera, el resultado sería "foo", y no "bar". Este comportamiento no parece estar documentado en ninguna parte, solo hay una breve nota acerca de que se eliminó en py3:
En Python 2, la siguiente declaración de subida es legal
aumentar ((E1, (E2, E3)), E4), V
El intérprete tomará el primer elemento de la tupla como el tipo de excepción (recursivamente), haciendo que el anterior sea completamente equivalente a
elevar E1, V
A partir de Python 3.0, se eliminará el soporte para aumentar tuplas como esta. Este cambio alineará las declaraciones de aumento con el método throw () en los objetos del generador, que ya no lo permite.