关于__new__丢失参数的最佳解决方案有什么建议?
今天我才意识到,从Python 2.6开始,__new__
这个方法不再支持接收参数了(在文档里没有提到这一点,而根据我所看到的,__new__
调用__init__
的行为也不太对)。这意味着我的一些功能代码开始出现警告,我想把这些警告去掉。但是我找不到一个优雅的解决办法。
我有一些类,在创建的时候会进行一些优化。所以我有:
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)
等等(实际的版本会处理更多的情况)。所以和Guido在这个回复中说的不同(这是我能找到的唯一参考),我的__new__
方法确实使用了它的参数,并且不能用重写的__init__
函数来替代。
我能做的最好的办法就是把它分成两部分:
def Conjunction(a, b):
if a == True:
return b
elif b == True
return a
else:
return ConjunctionImpl(a, b)
class ConjunctionImpl(Base):
# ...
但是这样看起来很丑,而且感觉很糟糕。我是不是漏掉了什么优雅的方法,可以让类的构造函数根据给定的参数返回一些任意的对象?
3 个回答
这让我很好奇,因为我在文档中没有看到这个功能被弃用,所以我自己试了一下。
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)
在这个例子中,你可以看到我重写了Foo类中的init方法,因为传给new的任何参数都会被转发到__new__
试图创建的类实例上。这个foo的实例将是Bar类的,但它会有成员a和b。我没有重写父类的__init__
方法,所以它会被调用。方法__new__
总是会把它的参数传给__init__
。如果你不重写对象的__init__
,那么会出错,因为那个方法不接受任何参数。
这就是我对Python 2.7中new用法的理解。根据文档,2.6的用法是类似的。
托马斯在他的回答中给了我正确的方向,但我想补充一下,在我的情况下,解决方案其实很简单:在我的基类中添加一个 __new__
方法,内容如下:
class Base(object):
def __new__(cls, *args, **kws):
instance = super(Base, cls).__new__(cls)
instance.__init__(*args, **kws)
return instance
__new__
方法并不是“不再接收参数”。在 Python 2.6 中发生的变化是,object.__new__
,也就是 object 类的 __new__
方法,不再忽略传入的参数了。(object.__init__
也不再忽略参数,不过在 2.6 中这只是个警告。)如果你想在调用 __new__
或 __init__
时传递参数,就不能把 object
作为你继承的终止类。
如果你希望你的代码在 2.6 中正常工作,就需要把 object
替换为一个合适的基类,这个基类能够正确接收额外的参数,并且在调用其他方法时(使用 super()
)不会把这些参数传递下去。