Death to tuples!

Duncan Booth duncan.booth at invalid.invalid
Wed Nov 30 03:41:51 EST 2005


Mike Meyer wrote:

>>> An object is compatible with an exception if it is either the object
>>> that identifies the exception, or (for exceptions that are classes)
>>> it is a base class of the exception, or it is a tuple containing an
>>> item that is compatible with the exception.
>>
>> Requiring a tuple here means that the code doesn't have to worry
>> about a possible recursive data structure.
> 
> How so?
> 
>     except ExceptType1, (ExceptType2, ExceptType3, (ExceptType4,
>     ExceptType5): 
> 
> I suspect this won't work, but meets the description.
> 
> Lists could be used here with the same restrictions as tuples.

I think you meant:

  except (ExceptType1, (ExceptType2, ExceptType3, (ExceptType4,
        ExceptType5))):

otherwise the first comma separates the exception specification from the 
target and you get a syntax error even before the syntax error you might 
expect from the unmatched parentheses. And yes, that works fine.

e.g. You can do this:

>>> ExcGroup1 = ReferenceError, RuntimeError
>>> ExcGroup2 = MemoryError, SyntaxError, ExcGroup1
>>> ExcGroup3 = TypeError, ExcGroup2
>>> try:
	raise ReferenceError("Hello")
except ExcGroup3, e:
	print "Caught",e

	
Caught Hello
>>> ExcGroup3
(<class exceptions.TypeError at 0x009645A0>, (<class exceptions.MemoryError 
at 0x00977120>, <class exceptions.SyntaxError at 0x00964A50>, (<class 
exceptions.ReferenceError at 0x009770C0>, <class exceptions.RuntimeError at 
0x00964840>)))
>>> 

The exception tuple has the same sort of nesting as your example, and no 
matter how deeply nested the system will find the relevant exception.

Now consider what happens if you used a list here:

>>> ExcGroup1 = [ReferenceError, RuntimeError]
>>> ExcGroup2 = MemoryError, SyntaxError, ExcGroup1
>>> ExcGroup3 = TypeError, ExcGroup2
>>> ExcGroup1.append(ExcGroup3)
>>> ExcGroup3
(<class exceptions.TypeError at 0x009645A0>, (<class exceptions.MemoryError 
at 0x00977120>, <class exceptions.SyntaxError at 0x00964A50>, [<class 
exceptions.ReferenceError at 0x009770C0>, <class exceptions.RuntimeError at 
0x00964840>, (<class exceptions.TypeError at 0x009645A0>, (<class 
exceptions.MemoryError at 0x00977120>, <class exceptions.SyntaxError at 
0x00964A50>, [...]))]))
>>> try:
	raise ReferenceError("Hello")
except ExcGroup3, e:
	print "Caught",e

	

Traceback (most recent call last):
  File "<pyshell#53>", line 2, in -toplevel-
    raise ReferenceError("Hello")
ReferenceError: Hello
>>>

As it currently stands, the exception is not caught because anything in the 
exception specification which is not a tuple is considered to be a 
(potential) exception.

With lists is suddenly becomes possible to have a recursive data structure. 
repr goes to a lot of effort to ensure that it can detect the recursion and 
replace that particular part of the output with ellipses. The exception 
handling code would have to do something similar if it accepted lists and 
that would slow down all exception processing. By only traversing inside 
tuples we can be sure that, even if the data structure as a whole is 
recursive, the part which is traversed is not.

(Note that the repr code also fails to detect the recursive tuple, it isn't 
until it hits the list a second time that it spots the recursion.)



More information about the Python-list mailing list