Hacking with __new__

Sandra-24 sandravandale at yahoo.com
Tue Jul 24 03:43:14 CEST 2007

Ok here's the problem, I'm modifying a 3rd party library (boto) to
have more specific exceptions. I want to change S3ResponseError into
about 30 more specific errors. Preferably I want to do this by
changing as little code as possible. I also want the new exceptions to
be a subclass of the old S3ResponseError so as to not break old code
that catches it. If I meet these two requirements I expect my
modification to make it into boto and then I won't have to worry about
maintaining a seperate version.

So thinking myself clever with python I thought I could change
S3ResponseError to have a __new__ method which returns one of the 30
new exceptions. That way none of the raise S3ResponseError code needs
changing. No problem. The trouble comes with those exceptions being
subclasses of S3ResponseError, because __new__ is called again and
goofs everything up.

I think there may be a way to solve this but after playing around in
the shell for a while, I give up. I'm less concerned with the original
problem than I am curious about the technical challenge. Can anyone
tell me if it's possible to do meet both of my requirements?


Here's my shell code if you want to play with it too (Bar is
S3ResponseError, Zoo is a more specific error, Foo is just the base
class of Bar.)

>>> class Foo(object):
...     def __new__(cls, *args):
...         print 'Foo.__new__', len(args)
...         return super(Foo, cls).__new__(cls, *args)
...     def __init__(self, a, b, c):
...         print 'Foo.__init__', 3
...         self.a = a
...         self.b = b
...         self.c = c
>>> class Bar(Foo):
...     def __new__(cls, a, b, c, *args):
...         print 'Bar.__new__', len(args)
...         if args:
...             return super(Bar, cls).__new__(cls, a, b, c, *args)
...         return Zoo(a, b, c, 7)
>>> class Zoo(Bar):
...     def __init__(self, a, b, c, d):
...         print 'Zoo.__init__', 4
...         Foo.__init__(self, a, b, c)
...         self.d = d
>>> Bar(1,2,3)
Bar.__new__ 0
Bar.__new__ 1
Foo.__new__ 4
Zoo.__init__ 4
Foo.__init__ 3
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: __init__() takes exactly 5 arguments (4 given)

More information about the Python-list mailing list