为什么Python在创建实例时不调用实例方法__init__(),而是调用类提供的__init__()呢?

14

我正在覆盖类的__new__()方法,以返回一个具有特定__init__()的类实例。但是Python似乎调用了提供的类的__init__()方法而不是特定实例的方法,尽管Python文档中说:

http://docs.python.org/reference/datamodel.html

  

典型的实现通过使用super(currentclass,cls).__new__(cls [,...])调用超类的 __new__() 方法并使用适当的参数创建类的新实例,然后根据需要修改新创建的实例后返回它。

     

如果__new__()返回cls的实例,则将像__init__(self [,...])一样调用新实例的__init__()方法,其中self是新实例,其余参数与传递给__new__()的参数相同。

以下是我的测试代码:

#!/usr/bin/env python

import new

def myinit(self, *args, **kwargs):
    print "myinit called, args = %s, kwargs = %s" % (args, kwargs)


class myclass(object):
    def __new__(cls, *args, **kwargs):
        ret = object.__new__(cls)

        ret.__init__ = new.instancemethod(myinit, ret, cls)
        return ret

    def __init__(self, *args, **kwargs):
        print "myclass.__init__ called, self.__init__ is %s" % self.__init__
        self.__init__(*args, **kwargs)

a = myclass()

这将输出

$ python --version
Python 2.6.6
$ ./mytest.py
myclass.__init__ called, self.__init__ is <bound method myclass.myinit of <__main__.myclass object at 0x7fa72155c790>>
myinit called, args = (), kwargs = {}

看起来唯一让 myinit() 运行起来的方式是在 myclass.__init__() 中显式地调用 self.__init__()

3个回答

11

新式类中的特殊方法是在实例类型上查找的,而不是在实例本身上查找。这是记录的行为

对于新式类,只有在对象类型中定义了特殊方法时,隐式调用特殊方法才能保证正常工作,而不是在对象实例字典中定义。这就是为什么下面的代码会引发异常(与旧式类的等效示例不同)的原因:

>>> class C(object):
...     pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()

8
各种特殊方法(包括__init__,以及运算符重载如__add__等)始终通过类而非实例访问。不仅如此,它们不能通过类或元类的__getattr____getattribute__方法访问,必须直接在类上。这是出于效率原因:

以这种方式绕过__getattribute__()机制为解释器内提供了显著的速度优化空间,但代价是在处理特殊方法时有一定的灵活性限制(特殊方法必须设置在类对象本身上,才能被解释器一致调用)。

不太清楚您想达到什么目的,但您可以在__new__方法中对myclass进行子类化:

class myclass(object):
    def __new__(cls, *args, **kwargs):
        class subcls(cls):
            def __new__(cls, *args, **kwargs):
                return object.__new__(cls)
        subcls.__init__ = myinit
        return subcls(*args, **kwargs)

0
为什么Python在实例创建时不调用实例方法init(),而是调用类提供的init()呢?
看看这个例子。
class C:
   one = 42
   def __init__(self,val):
        self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)

结果会是这样的:
{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}

请注意,只有值{'two': 50}是实例字典的一部分。 'one': 42属于类C字典。 __init__方法也是如此。
这是按设计要求执行的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接