Any ideas about the best work around for __new__ losing its arguments?
So, I only realised today that __new__
is deprecated for receiving arguments, as of python 2.6 (it isn't mentioned in the documentation, which is also not true in terms of the behavior of __new__
calling __init__
as far as I can see). This means my functional code has started raising warnings, and I want to rid myself of them. But I can't see an elegant way to work around.
I have a bunch of classes that perform optimizations when they are constructed. So I have
class Conjunction(Base):
def __new__(cls, a, b):
if a == True:
return b
elif b == True
return a
else:
return super(Conjunction,cls).__new__(cls, a, b)
And so on (real versions cover lots more cases). So unlike what Guido says in this response (the only reference to it I can find), my __new__
method does use its arguments, and cannot be replaced by an overridden __init__
function.
The best I can do is to split this in two:
def Conjunction(a,开发者_JAVA百科 b):
if a == True:
return b
elif b == True
return a
else:
return ConjunctionImpl(a, b)
class ConjunctionImpl(Base):
# ...
But that is plain ugly and stinks to high heaven. Am I missing an elegant way to have a class constructor return some arbitrary object based on the constructor parameters it is given?
__new__
is not "deprecated for receiving arguments". What changed in Python 2.6 is that object.__new__
, the __new__
method of the object class, no longer ignores any arguments it's passed. (object.__init__
also doesn't ignore the arguments anymore, but that's just a warning in 2.6.) You can't use object
as the terminating class for your inheritance if you want to pass arguments to __new__
or __init__
.
In order for any code to rely on that behaviour to work in 2.6, you just have to replace object
as the baseclass, using a baseclass that properly accepts the extra arguments and does not pass them along in the calls it makes (using super()
.)
Thomas put me right in his answer, but I should add that the solution in my case was trivial: add a __new__
method to my base class with the lines:
class Base(object):
def __new__(cls, *args, **kws):
instance = super(Base, cls).__new__(cls)
instance.__init__(*args, **kws)
return instance
Well this made me curious because I did not see the deprecation in the documentation so I gave it a try myself.
class Foo(object):
def __new__(cls, a, b):
if a:
return a
elif b:
return b
else:
return super(Foo, cls).__new__(cls, a, b)
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
def __new__(cls, x, y):
if x:
return x
if y:
return y
else:
return super(Bar, cls).__new__(cls, x, y)
foo = Bar(False, False)
As you can see in this example I overrode the init in Foo because any args passed to new will be forwarded to the cls instance that __new__
attempts to create. The instance of foo with be of a Bar class but it will have members a and b. I caused the super class's __init__
to be called by not overriding it. The method __new__
always passes its args on to __init__
. If you don't override the __init__
for object it will fail since that method takes no args.
That's my take on the usage of new in Python 2.7. According to the docs 2.6 is similar.
精彩评论