Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why raising a tuple works if first element is an Exception?

Tags:

I have a hard time figuring this one out, it's about mistakes that can be done when raising an exception in Python 2.7:

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

the message here is "exceptions must be old-style classes or derived from BaseException, not list" - This part is ok, but when I change it to tuple, I am getting confused:

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

the message here is "exceptions must be old-style classes or derived from BaseException, not int" - why is it interpreted as raising an int, not a tuple?

Futhermore:

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

Here we are actually rising an Exception (consistent behaviour when compared with previous example, where we were raising an int) - I briefly thought that this is just an alternate way for this:

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

But in this case, 'a message' is being passed to Exceptions ctor (as documented on docs.python.org)

Can someone explain the 2nd and 3rd cases, and possible point me to code in interpreter that is responsible for this?

like image 614
dahpgjgamgan Avatar asked Mar 23 '12 09:03

dahpgjgamgan


People also ask

Does raising an exception stop execution Python?

except block is completed and the program will proceed. However, if an exception is raised in the try clause, Python will stop executing any more code in that clause, and pass the exception to the except clause to see if this particular error is handled there.

What happens when an exception is raised in Python?

When an exception is raised, no further statements in the current block of code are executed. Unless the exception is handled (described below), the interpreter will return directly to the interactive read-eval-print loop, or terminate entirely if Python was started with a file argument.

When should you raise an exception Python?

Use raise when you know you want a specific behavior, such as: raise TypeError("Wanted strawberry, got grape.") Raising an exception terminates the flow of your program, allowing the exception to bubble up the call stack.

Can you have a tuple with one element?

To create a tuple with only one item, you have add a comma after the item, otherwise Python will not recognize the variable as a tuple.


1 Answers

As documented in the Python 2 reference, the raise statement takes up to 3 expressions to create the exception being raised:

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

If the first expression is a tuple, python will 'unwrap' the tuple recursively, taking the first element until it finds something other than a tuple. This behavior is being removed from Python 3 (see PEP 3109). The following is legal:

>>> raise ((Exception, 'ignored'), 'ignored'), 'something', None Traceback (most recent call last):   File "<stdin>", line 1, in <module> Exception: something 

The documentation explains the rest in more detail, but the raise statement expects the first value to be a Exception class, the second value is seen as the value of the exception (the message) and the third value is a traceback. Python fills in None for the latter two values if missing.

If the first value is a instance instead, the second value must be 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 

If you use a tuple of more than 3 items, it'll raise a syntax error:

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

In your case however, you raised neither a class nor an instance, so that's what Python found to be incorrect first; if I use a string it'll complain too:

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

The correct syntax is of course:

>>> raise Exception, 'something', None Traceback (most recent call last):   File "<stdin>", line 1, in <module> Exception: something 
like image 146
Martijn Pieters Avatar answered Sep 28 '22 01:09

Martijn Pieters