【问题标题】:Why doesn't Python call instance method __init__() on instance creation but calls class-provided __init__() instead?为什么 Python 在创建实例时不调用实例方法 __init__() 而是调用类提供的 __init__() ?
【发布时间】:2012-07-23 01:03:22
【问题描述】:

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

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

说:

典型的实现通过调用 使用 super(currentclass, cls).__new__(cls[, ...]) 的超类的 __new__() 方法 使用适当的参数,然后将新创建的实例修改为 退货前需要。

如果 __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() 运行的唯一方法是在myclass.__init__() 内显式调用它为self.__init__()

【问题讨论】:

    标签: python object methods instances


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        为什么 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__ 方法也是如此。

        这是每个设计。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-11-06
          • 2014-11-28
          • 1970-01-01
          • 1970-01-01
          • 2011-04-16
          • 2016-06-11
          • 2019-08-21
          相关资源
          最近更新 更多