14

我正在覆盖__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()运行的方法是将其明确称为self.__init__()inside myclass.__init__()

4

3 回答 3

11

Special methods on new-style classes are looked up on the instance's type, not on the instance itself. This is documented behaviour:

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

>>> 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()
于 2012-07-24T16:45:14.357 回答
8

各种特殊方法(包括__init__,但也包括运算符重载,例如__add__等)总是通过类而不是实例访问。不仅如此,它们不能通过类或元类上的__getattr__or__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).

It's not entirely clear what you're trying to accomplish, but one thing you could do here is to subclass myclass within the __new__ method:

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)
于 2012-07-24T16:45:03.987 回答
0

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

Check out this example.

class C:
   one = 42
   def __init__(self,val):
        self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)

The result will be like this:

{'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}

Note that only the value {'two': 50} is part of the instance dict.

'one': 42 belongs to a class C dict. The same is with the __init__ method.

This is per design.

于 2019-06-04T09:13:53.950 回答