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

时间:2012-07-24 16:41:31

标签: python object methods instances

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

中的Python文档

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

表示:

  

典型的实现通过调用来创建类的新实例   superclass的__new __()方法使用super(currentclass,cls).__ new __(cls [,...])   使用适当的参数,然后将新创建的实例修改为   在返回之前必要的。

     

如果__new __()返回cls的实例,那么新实例的__init __()方法   将像__init __(self [,...])一样被调用,其中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__()

3 个答案:

答案 0 :(得分: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()

答案 1 :(得分:8)

各种特殊方法(包括__init__,还有__add__等运算符重载)都是always accessed via the class rather than the instance。不仅如此,它们无法通过类或元类的__getattr____getattribute__方法访问,它们必须直接在类上。这是出于效率的原因:

  

以这种方式绕过__getattribute__()机制为解释器内的速度优化提供了很大的空间,代价是处理特殊方法的一些灵活性(必须在类对象本身上按顺序设置特殊方法由翻译一致地调用。)

您要完成的目标并不完全清楚,但您可以做的一件事是在myclass方法中继承__new__

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)

答案 2 :(得分: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__方法也是如此。

这是根据设计。