首页 文章

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

提问于
浏览
11

我正在覆盖类的 __new__() 方法,以返回具有特定 __init__() 集的类实例 . Python似乎调用类提供的 __init__() 方法而不是特定于实例的方法,尽管Python文档在

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

说:

典型实现通过使用具有适当参数的super(currentclass,cls).__ new __(cls [,...])调用超类的__new __()方法创建类的新实例,然后根据需要修改新创建的实例 . 归还它 . 如果__new __()返回一个cls实例,那么新实例的__init __()方法将被调用,如__init __(self [,...]),其中self是新实例,其余参数与传递给的相同 . () .

这是我的测试代码:

#!/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__() .

2 回答

  • 9

    关于新样式类的特殊方法是在实例的类型上查找,而不是在实例本身上查找 . 这是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()
    
  • 8

    各种特殊方法(包括 __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)
    

相关问题