473,394 Members | 2,048 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Hacking with __new__

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?

Thanks,
-Sandra

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)

Jul 24 '07 #1
5 1426
Sandra-24 <sa***********@yahoo.comwrote:
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 what you want for Bar is something more along the lines:

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)
target = cls
if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if args:
return obj

obj.__init__(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)

Output from this is:

Bar.__new__ 0
Foo.__new__ 3
Zoo.__init__ 4
Foo.__init__ 3

Bar can instantiate a subclass, but to do that it wants to call the
constructor __new__ only for the base classes, and because it has
changed the type of the object being constructed it has to call __init__
explicitly.
Jul 24 '07 #2
Duncan Booth a écrit :
(snip)
I think what you want for Bar is something more along the lines:
(snip)
class Bar(Foo):
def __new__(cls, a, b, c, *args):
print 'Bar.__new__', len(args)
target = cls
You don't use 'target' anywhere...
if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if args:
return obj

obj.__init__(a, b, c, 7)
IIRC, __new__ is supposed to return the newly created object - which you
are not doing here.

class Bar(Foo):
def __new__(cls, a, b, c, *args):
print 'Bar.__new__', len(args)
if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if not args:
obj.__init__(a, b, c, 7)
return obj
Jul 24 '07 #3
On Jul 24, 5:20 am, Bruno Desthuilliers <bruno.
42.desthuilli...@wtf.websiteburo.oops.comwrote:
IIRC, __new__ is supposed to return the newly created object - which you
are not doing here.

class Bar(Foo):
def __new__(cls, a, b, c, *args):
print 'Bar.__new__', len(args)
if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if not args:
obj.__init__(a, b, c, 7)
return obj
Thanks guys, but you are right Bruno, you have to return the newly
created object or you get:
>>b = Bar(1,2,3)
Bar.__new__ 0
Foo.__new__ 3
Zoo.__init__ 4
Foo.__init__ 3
>>b is None
True

However, if you return the object you get:
>>b = Bar(1, 2, 3)
Bar.__new__ 0
Foo.__new__ 3
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)

Which is the same blasted error, because it seems to want to call init
on the returned object and it's calling it with 4 args :( Is there any
way around that?

Thanks,
-Sandra
Jul 24 '07 #4
Bruno Desthuilliers <br********************@wtf.websiteburo.oops.com >
wrote:
Duncan Booth a écrit :
(snip)
>I think what you want for Bar is something more along the lines:

(snip)
>class Bar(Foo):
def __new__(cls, a, b, c, *args):
print 'Bar.__new__', len(args)
target = cls
You don't use 'target' anywhere...
> if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if args:
return obj

obj.__init__(a, b, c, 7)

IIRC, __new__ is supposed to return the newly created object - which you
are not doing here.
Yup. I committed that cardinal sin of checking the code and then tidying it
up by hand but not checking the tidied version. :(
Jul 24 '07 #5
On 7/24/07, Sandra-24 <sa***********@yahoo.comwrote:
On Jul 24, 5:20 am, Bruno Desthuilliers <bruno.
42.desthuilli...@wtf.websiteburo.oops.comwrote:
IIRC, __new__ is supposed to return the newly created object - which you
are not doing here.

class Bar(Foo):
def __new__(cls, a, b, c, *args):
print 'Bar.__new__', len(args)
if not args:
cls = Zoo
obj = super(Bar, cls).__new__(cls, a, b, c, *args)
if not args:
obj.__init__(a, b, c, 7)
return obj

Thanks guys, but you are right Bruno, you have to return the newly
created object or you get:
>b = Bar(1,2,3)
Bar.__new__ 0
Foo.__new__ 3
Zoo.__init__ 4
Foo.__init__ 3
>b is None
True

However, if you return the object you get:
>b = Bar(1, 2, 3)
Bar.__new__ 0
Foo.__new__ 3
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)

Which is the same blasted error, because it seems to want to call init
on the returned object and it's calling it with 4 args :( Is there any
way around that?
__init__ is going to be called with the arguments passed to __new__
and there doesn't seem to be any way to affect that. Your only option
to make it not happen is for Zoo not to be a subclass of Bar.

Possible workarounds:
Each subclass of Bar needs a corresponding __new__

Each subclass of Bar needs a cooperating __init__ that detects (via
optional arguments) if it's being called by Bar.__new__ or directly
and noops in the second case.
Jul 24 '07 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Michele Simionato | last post by:
Let me show first how does it work for tuples: >>> class MyTuple(tuple): .... def __new__(cls,strng): # implicit conversion string of ints => tuple .... return...
9
by: Felix Wiemann | last post by:
Sometimes (but not always) the __new__ method of one of my classes returns an *existing* instance of the class. However, when it does that, the __init__ method of the existing instance is called...
5
by: could ildg | last post by:
As there is already __init__, why need a __new__? What can __new__ give us while __init__ can't? In what situations we should use __new__? And in what situations we must use __new__? Can __new__...
3
by: James Stroud | last post by:
Hello All, I'm running 2.3.4 I was reading the documentation for classes & types http://www.python.org/2.2.3/descrintro.html And stumbled on this paragraph: """ __new__ must return an...
5
by: Ken Schutte | last post by:
Hi, I'm been trying to create some custom classes derived from some of python's built-in types, like int and list, etc. I've run into some trouble, which I could explain with a couple simple...
18
by: Paulo da Silva | last post by:
Sorry to put here too many questions about __init__ __new__ stuff but I always found a new problem when using them. I have searched for simple __new__ docs on how to do the basic things but find...
1
by: Frank Benkstein | last post by:
Hi, the behaviour I always observed when creating instances by calling the class A is that '__init__' is always only called when the object returned by A.__new__ is an instance of A. This can be...
4
by: Steven D'Aprano | last post by:
When you call a new-style class, the __new__ method is called with the user-supplied arguments, followed by the __init__ method with the same arguments. I would like to modify the arguments...
3
by: Torsten Mohr | last post by:
Hi, i have some questions related to new style classes, they look quite useful but i wonder if somebody can give me an example on constructors using __new__ and on using __init__ ? I just see...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.