args attribute of Exception objects

Bengt Richter bokr at oz.net
Tue Apr 12 06:19:07 EDT 2005


On 12 Apr 2005 01:57:31 -0700, sdementen at hotmail.com (Sebastien de Menten) wrote:

>Thank you guys for those good advices (and the very interesting
>example of AST hacking).
>
>However, this was an example of use for Exception.args. It does not
>alleviate my concerns about the fact that the args attribute is poorly
>designed for standard Exceptions.
>It is as if the Exception design was only made for end users (display
>of a string in an interpreter) without thinking about original ways to
>use them :-)
>
Look into it some more ;-)

Have you thought of subclassing Exception for your own purpose?
You can override the base exception class's Exception.__init__
which UIAM effectively does

    def __init__(self, *args):
        self.args = args

and no more. Using an existing special purpose exception like NameError
(IIRC seeing that correctly) to carry info for you is pretty weird ;-)

Here is a subclass that takes what would be e.args[0] and delivers it
instead as e.answer (well, "e" is "retans" below ;-)

 >>> class BailingOutWithAnswer(Exception):
 ...     def __init__(self, answer):
 ...         self.answer = answer
 ...
 >>> for ans in ['string', 123, 4.5, 67L, 8+9j,
 ...         type('MyClass',(),{}), type('MyInst',(),{})()]:
 ...     try: raise BailingOutWithAnswer(ans)
 ...     except BailingOutWithAnswer, retans:
 ...         print '%r -> retans.answer: %r' %(ans, retans.answer)
 ...
 'string' -> retans.answer: 'string'
 123 -> retans.answer: 123
 4.5 -> retans.answer: 4.5
 67L -> retans.answer: 67L
 (8+9j) -> retans.answer: (8+9j)
 <class '__main__.MyClass'> -> retans.answer: <class '__main__.MyClass'>
 <__main__.MyInst object at 0x02EF14EC> -> retans.answer: <__main__.MyInst object at 0x02EF14EC>

It's the easiest thing in the world to define a minimal Exception subclass to give you
back in e.args whatever you pass it as args when you raise it. Obviously I could have used
a table of arg tuples and just raise XEasy(*argtuples[i]) instead of separating them out,
but I wanted to show how plain raise expression syntax with
different numbers of arguments map to e.args.

 >>> class XEasy(Exception): pass
 ...
 >>> for i in xrange(7):
 ...     try:
 ...         if i==0: raise XEasy(123)
 ...         elif i==1: raise XEasy(4.5, 67L)
 ...         elif i==2: raise XEasy(*'this may seem tricky ;-)'.split())
 ...         elif i==3: raise XEasy, 'usual ordinary message form'
 ...         elif i==4: raise XEasy(8+9j, type('AClass',(),{}))
 ...         elif i==5: raise XEasy(type('AClass',(),{})(),'<=[class instance]')
 ...         elif i==6: raise XEasy('--------------------------------------------')
 ...     except XEasy, e:
 ...         print e.args
 ...
 (123,)
 (4.5, 67L)
 ('this', 'may', 'seem', 'tricky', ';-)')
 ('usual ordinary message form',)
 ((8+9j), <class '__main__.AClass'>)
 (<__main__.AClass object at 0x02EF166C>, '<=[class instance]')
 ('--------------------------------------------',)

Oops, left out the no-arg raises

 >>> try: raise XEasy
 ... except XEasy, e: print e.args
 ...
 ()
 >>> try: raise XEasy()
 ... except XEasy, e: print e.args
 ...
 ()

Did I misunderstand the problem again?

Regards,
Bengt Richter



More information about the Python-list mailing list