假设我有一些调用__new__
的类,如何根据需要调用mro并调用超类'__new__
(带参数),但不调用{{1附加参数?例如。这只有在你没有向构造函数传递参数时才有效:
object.__new__
但是使用参数调用会导致它失败(因为在某些时候Python更改为class A(object):
def __new__(cls, *args, **kwargs):
print("A.__new__ called")
return super(A, cls).__new__(cls, *args, **kwargs)
class B(object):
def __new__(cls, *args, **kwargs):
print("B.__new__ called")
return super(B, cls).__new__(cls, *args, **kwargs)
class C(A, B): pass
>>> C.mro()
[__main__.C, __main__.A, __main__.B, builtins.object]
>>> C()
A.__new__ called
B.__new__ called
除了调用者类之外不接受任何参数):
object.__new__
那么>>> C(1)
A.__new__ called
B.__new__ called
Traceback (most recent call last):
...
TypeError: object() takes no parameters
或A
如何判断他们的超级班级是B
?我应该做object
之类的事吗?检查super(A, cls).__new__ is object.__new__
?或者我只需要决定“A将从不尝试在mro()[1] == builtins.object
中很好地调用超类”(例如通过__new__
执行)?
编辑:如果类定义了一个自定义return object.__new__(cls)
方法,Python 2.6和Python 2.7就可以了,但它仍然 在Python 3中工作。
答案 0 :(得分:9)
如果我们查看CPython source,我们会看到:
object.__new__
将会出错,并且__new__
被覆盖或__init__
未被覆盖;同样地,object.__init__
将会出错,并且__init__
被覆盖或__new__
不被覆盖在2.x中,错误只是DeprecationWarning
,您可能在实验时可能错过了(请注意,因为2.7和3.2 DeprecationWarning
是suppressed by default)。
这种行为的理由是类型是不可变的 - 在这种情况下它们应该使用__new__
中的参数 - 或者是可变的 - 在这种情况下它们应该使用__init__
中的参数。这似乎是一个实用性节拍纯度的案例;很难想到许多高效使用__new__
委托超类型(而不仅仅是记录/跟踪),而且{{1}会更常见。用额外的参数调用super
是一个错误。
最简单的方法是检查身份:object.__new__
。理由:
这就是CPython决定是否出错的方式(在C而不是Python中,但逻辑是相同的):
super(A, cls).__new__ is object.__new__
if (excess_args(args, kwds) &&
(type->tp_init == object_init || type->tp_new != object_new)) {
PyErr_SetString(PyExc_TypeError, "object() takes no parameters");
return NULL;
}
对参数没有任何作用,除了决定是否出错。
答案 1 :(得分:2)
自定义__new__
方法实际上不能传递它自己使用和需要的参数。如果C
,B
或A
都不需要参数,则object.__new__()
引发异常的事实完全正确。
请注意,由于很快,因为您有自定义__init__
以及,因此object.__new__
也不会引发异常。那是因为现在有一些地方可以将剩余的参数交给:
>>> class A(object):
... def __new__(cls, *args, **kwargs):
... print("A.__new__ called")
... return super(A, cls).__new__(cls, *args, **kwargs)
...
>>> class B(object):
... def __new__(cls, *args, **kwargs):
... print("B.__new__ called")
... return super(B, cls).__new__(cls, *args, **kwargs)
...
>>> class C(A, B):
... def __init__(self, *args, **kwargs):
... print args, kwargs
...
>>> C(1)
A.__new__ called
B.__new__ called
(1,) {}
<__main__.C object at 0x10e7f9790>
在Python 3中似乎发生了这种行为。
您可以测试以查看返回的__new__
方法:
class B(object):
def __new__(cls, *args, **kwargs):
new = super(B, cls).__new__
if new is object.__new__:
return new(cls)
return new(cls, *args, **kwargs)