[Python-3000] removing exception .args
Nick Coghlan
ncoghlan at gmail.com
Sat Jul 21 20:02:57 CEST 2007
Andrew Dalke wrote:
> Having support for a single object (almost always a
> string) passed into the exception is pragmatically useful,
> so I think the base exception class should look like
>
> class Exception(object):
> msg = None
> def __init__(self, msg):
> self.msg = msg
> def __str__(self):
> if self.msg is not None:
> return "%s()" % (self.__class__.__name__,)
> else:
> return "%s(%r)" % (self.__class__.__name__, self.msg)
>
> **
Went there, didn't like it, left again. See PEP 352, especially the
section on the late (unlamented) BaseException.message.
> The rest of this email is because I'm detail oriented
> and present evidence to back up my assertion.
>
> There are a number of subclasses which should but don't
> call the base __init__, generic error reporting software
> can't use the "args protocol" for anything. Pretty much
> the only thing a generic error report mechanism (like
> traceback and logging) can do is call str() on the exception.
As of Python 2.5, you can rely on the attribute being present, as it is
provided automatically by BaseException:
.>>> class MyException(Exception):
... def __init__(self):
... pass
...
.>>> MyException().args
()
Of course, as Guido pointed out, args will be empty unless the exception
sets it directly or via BaseException.__init__.
> This is correct, but cumbersome. Why should we
> encourage all non-trivial subclasses to look like this?
If you want to avoid requiring that subclasses call your __init__
method, you can actually do that by putting any essential initialisation
into the __new__ method instead. Then the requirement is merely to call
the parent __new__ method if you override __new__, and you have to do
something like that in order to create the class instance in the first
place.
To rewrite the example from getopt using this technique:
class GetoptError(Exception):
def __new__(cls, msg, opt=''):
self = super(cls, GetoptError).__new__(cls, msg, opt='')
self.msg = msg
self.opt = opt
return self
def __str__(self):
return self.msg
I actually find using __new__ this way to be a useful practice in
general for setting up class invariants in base classes, as it's easy to
forget to call __init__ on the base class, but forgetting to call
__new__ takes some serious effort. Putting the essential parts in
__new__ means never having to include the instruction that "you must
call this classes __init__ method when subclassing and overriding
__init__" into any API documentation I write.
Regards,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://www.boredomandlaziness.org
More information about the Python-3000
mailing list