为什么Python不调用实例方法__init __()创建实例,而是调用类提供的__init __()来代替?

问题描述:

我在覆盖__new__()方法返回一个具有特定__init__()集合的类实例。蟒蛇似乎在为什么Python不调用实例方法__init __()创建实例,而是调用类提供的__init __()来代替?

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

调用这个类提供的__init__()方法,而不是特定实例的方法,虽然Python的文件说:

典型实现创建由类的新实例使用super(currentclass,cls).__ new __(cls [,...]) 调用 超类的__new __()方法,然后在返回它之前修改新创建的实例为 。

如果__new __()返回CLS的实例,那么新实例的__init __()方法 将被调用像__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()运行,是显式调用它self.__init__()myclass.__init__()

+1

大问题! – Marcin 2012-07-24 16:49:29

新样式类特殊的方法是看取决于实例的类型,而不是实例本身。这是documented behaviour

对于新样式类,特殊的方法调用隐含只能保证,如果一个对象的类型定义,而不是在对象的实例字典才能正常工作。这种行为就是为什么下面的代码会引发异常(不像相当于例如使用老式类)的原因:

>>> 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() 

各种特殊方法(包括__init__,还有运营商过载如__add__等)都是always accessed via the class rather than the instance。不仅如此,它们不能通过类或元类上的__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)