确定在Python 3中super().__ new__是否为object .__ new__?

时间:2013-10-31 23:00:31

标签: python python-3.x super

假设我有一些调用__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中工作。

2 个答案:

答案 0 :(得分:9)

如果我们查看CPython source,我们会看到:

    如果使用额外参数调用
  • object.__new__将会出错,并且__new__被覆盖或__init__ 未被覆盖;同样地,
  • 如果使用额外参数调用
  • object.__init__将会出错,并且__init__被覆盖或__new__ 被覆盖

在2.x中,错误只是DeprecationWarning,您可能在实验时可能错过了(请注意,因为2.7和3.2 DeprecationWarningsuppressed 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__方法实际上不能传递它自己使用和需要的参数。如果CBA都不需要参数,则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)