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