如果定义了超类__new__,则不调用子类__init__

时间:2017-12-08 19:05:05

标签: python

请参阅以下ipython会话:

$ ipython --no-banner

In [1]: class foo(object):
   ...:     def __new__(self, *args, **kwargs):
   ...:         print 'in superclass __new__'
   ...:         return self
   ...: 
   ...: class bar(foo):
   ...:     def __init__(self, *args, **kwargs):
   ...:         print 'in subclass __init__'
   ...:         self.val = 42
   ...:         

In [2]: b = bar()
in superclass __new__

In [3]: b.val
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-c55d38c9d4d9> in <module>()
----> 1 b.val

AttributeError: type object 'bar' has no attribute 'val'

这里发生了什么?为什么在__new__中定义foo会阻止__init__bar中投放?

3 个答案:

答案 0 :(得分:3)

您将从__new__返回无效值。引用the documentation

  

如果__new__()返回 cls 的实例,则会调用新实例的__init__()方法...如果__new__()未返回实例 cls ,然后不会调用新实例的__init__()方法。

请注意__new__的第一个参数是一个类,而不是一个对象。 __new__的工作是分配对象,通常是通过调用super().__new__

试试这个:

class foo(object):
    def __new__(cls, *args, **kwargs):
        print 'in superclass __new__'
        return super(foo, cls).__new__(cls, *args, **kwargs)

class bar(foo):
    def __init__(self, *args, **kwargs):
        print 'in subclass __init__'
        self.val = 42

b = bar()
print b

答案 1 :(得分:3)

来自datamodel文档:

  

如果__new__()未返回cls的实例,则不会调用新实例的__init__()方法。

所以,请再试一次:

class foo(object):
    def __new__(cls, *args, **kwargs):
        print 'in superclass __new__'
        return super(foo, cls).__new__(cls, *args, **kwargs)

class bar(foo):
    def __init__(self, *args, **kwargs):
        print 'in subclass __init__'
        self.val = 42

答案 2 :(得分:3)

您的__new__功能签名意味着您不太了解发生了什么。 __new__的第一个参数是,调用它self通常用于实例应该是一个警告:{{1是构造函数,实例尚不存在。所以会发生什么事情,你要返回一个与类不同的类型的对象(实际上 类,所以类型为__new__)因此, type已被跳过!你想要这样的东西:

__init__