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

Why doesn't Python call instance method __init__() on instance creation but calls class-provided __init__() instead?

我重写了类的__new__()方法以返回具有特定__init__()集的类实例。虽然python文档位于

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

说:

Typical implementations create a new instance of the class by invoking the
superclass’s __new__() method using super(currentclass, cls).__new__(cls[, ...])
with appropriate arguments and then modifying the newly-created instance as
necessary before returning it.

If __new__() returns an instance of cls, then the new instance’s __init__() method
will be invoked like __init__(self[, ...]), where self is the new instance and the
remaining arguments are the same as were passed to __new__().

这是我的测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/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()

哪些输出

1
2
3
4
5
$ 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__()


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

For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary. That behaviour is the reason why the following code raises an exception (unlike the equivalent example with old-style classes):

1
2
3
4
5
6
7
8
9
>>> 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__等)总是通过类而不是实例访问。不仅如此,它们不能通过类或元类上的__getattr____getattribute__方法访问,它们必须直接在类上。这是为了提高效率:

Bypassing the __getattribute__() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).

目前还不完全清楚您试图完成什么,但您可以在这里做的一件事是在__new__方法中对myclass进行子类划分:

1
2
3
4
5
6
7
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)