2012-03-23 10 views
19

que tienen dificultades para averiguar éste hacia fuera, se trata de errores que se pueden hacer al levantar una excepción en Python 2.7:¿Por qué levantar una tupla funciona si el primer elemento es una excepción?

try: 
    raise [1, 2, 3, 4] 
except Exception as ex: 
    print ex 

el mensaje aquí es "excepciones deben ser clases de estilo antiguo o derivados de BaseException , no lista" - Esta parte está bien, pero cuando lo cambio a tupla, me estoy confundido:

try: 
    raise (1, 2, 3, 4) 
except Exception as ex: 
    print ex 

el mensaje aquí es 'excepciones deben ser clases de estilo antiguo o derivado de BaseException, no int' - ¿Por qué se interpreta como elevar una int, no una tupla?

Futhermore:

try: 
    raise (Exception, 'a message') 
except Exception as ex: 
    print ex 

Aquí estamos en realidad el aumento de una excepción (un comportamiento coherente en comparación con el ejemplo anterior, donde nos planteamos un int) - pensé brevemente que esto es sólo una forma alternativa para esto:

try: 
    raise Exception, 'a message' 
except Exception as ex: 
    print ex 

Pero en este caso, 'un mensaje' se está pasando a Héctor excepciones (como se documenta en docs.python.org)

Puede alguien se expl en los casos segundo y tercero, y es posible que me indiquen un código en el intérprete que es responsable de esto?

Respuesta

15

Como documented in the python reference, la declaración raise puede durar hasta 3 expresiones para crear la excepción siendo elevada:

raise_stmt ::= "raise" [expression ["," expression ["," expression]]]

en Python 2, si la primera expresión es una tupla, Python 'Separar' la tupla de forma recursiva, teniendo el primer elemento hasta que encuentra algo que no sea una tupla. Este comportamiento se está eliminando de Python 3 (consulte PEP 3109.El 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 sentencia raise espera que el primer valor a ser una clase de excepción, el segundo valor es visto como el valor de la excepción (el mensaje) y el tercer valor es un traceback. Python rellena None para los dos últimos valores si falta.

Si el primer valor es una instancia en cambio, el segundo valor debe ser None:

>>> 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 utiliza una tupla de más de 3 artículos, que va a elevar una sintaxis de error:

>>> raise Exception, 'something', None, None 
    File "<stdin>", line 1 
    raise Exception, 'something', None, None 
            ^
SyntaxError: invalid syntax 

En su caso, sin embargo, se levantó ni una clase ni una instancia, así que eso es lo que Python resultó ser incorrecta primero; si uso una cadena que va a quejarse demasiado:

>>> 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 
+0

yo no era consciente de la tupla desenvolver recursiva, así que no podía ver por qué los otros elementos son ignorados - el PEP era el eslabón perdido que estaba buscando. – dahpgjgamgan

3

http://docs.python.org/reference/simple_stmts.html#the-raise-statement

"elevar" [expresión [expresión [ "" "" expresión]]]

Si no hay expresiones están presentes, aumentar la re-plantea la última excepción de que era activo 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é pitón no tupla desembalaje 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 ser documentado en ninguna parte, sólo hay una breve nota de ello se redujo en el AP3:

In Python 2, the following raise statement is legal

raise ((E1, (E2, E3)), E4), V

The interpreter will take the tuple's first element as the exception type (recursively), making the above fully equivalent to

raise E1, V

As of Python 3.0, support for raising tuples like this will be dropped. This change will bring raise statements into line with the throw() method on generator objects, which already disallows this.

http://www.python.org/dev/peps/pep-3109/#id17

+1

no veo la forma en que responde a la pregunta. ¿Le importaria explicar? –

+1

Para ser un poco más claro acerca de mi comentario: Claramente la tupla se evalúa para que el primer elemento devuelto. ¿Por qué esto no sucede con el argumento de la lista? –

+0

Parece que las tuplas se desempaquetan automáticamente para el aumento (y las listas no se pudieron desempaquetar). – kosii

3

Al parecer Python acepta también una tupla no vacía por primera expresión en una sentencia raise a pesar la documentación (pero como se indica en this PEP), y si es una tupla, usa recursivamente su primer elemento para la clase de la excepción. Te voy a enseñar algo de 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 he dicho en mi comentario anterior, no hay auto-desembalaje, ya que 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 usando el módulo Python ast, podemos ver que en una expresión que no hay aumento 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 utilizamos una tupla, que se pasa como argumento 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)])" 
Cuestiones relacionadas