需要了解__init__、__new__和__call__的流程

Posted

技术标签:

【中文标题】需要了解__init__、__new__和__call__的流程【英文标题】:need to understand the flow of __init__, __new__ and __call__ 【发布时间】:2012-10-09 21:56:17 【问题描述】:
class Singleton(type):
    def __init__(self, *args, **kwargs):
        print 'calling __init__ of Singleton class', self
        print 'args: ', args
        print 'kwargs: ', kwargs
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        print 'running __call__ of Singleton', self
        print 'args: ', args
        print 'kwargs: ', kwargs, '\n\n'
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

class A(object):
    __metaclass__ = Singleton
    def __init__(self,a):
        print 'in __init__ of A:  ', self
        self.a = a
        print 'self.a: ', self.a

a=A(10)
b=A(20)

我从 Ben 对问题 Python's use of __new__ and __init__? 的回答中复制了这段代码,并对其进行了一些修改。但是,我不知道流量。尽管我从更高的层次上理解了这段代码的目的。但是,在内部它是如何工作的,我不太确定。

运行此代码时,我得到以下输出:-

calling __init__ of Singleton class <class '__main__.A'>
args:  ('A', (<type 'object'>,), '__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>)
kwargs:  
running __call__ of Singleton <class '__main__.A'>
args:  (10,)
kwargs:  


in __init__ of A:   <__main__.A object at 0x01FA7A10>
self.a:  10
running __call__ of Singleton <class '__main__.A'>
args:  (20,)
kwargs:  

我不明白__init____call__argskwargs 是如何变得不同的。 在使用元类时,此链接 (What is a metaclass in Python?) 解释了如何使用 __new__ 和函数作为元类。但是,我不明白__call__ 是如何被使用的。

有人能解释一下流程吗?我的意思是,__new____call____init__ 被调用的优先级以及谁调用它们?

【问题讨论】:

问题是,你做什么? 我是许多 python 概念的新手。我正在尝试实现本在链接中的回答中提到的 Singleton 类:***.com/questions/674304/pythons-use-of-new-and-init。另外,在实现过程中,我想了解我编写的程序的内部流程。 你读过documentation吗?我强烈建议您完整阅读该页面。 是的,但是,它的解释不如 glglgl 在下面的回答中解释的那样。 【参考方案1】:

您的代码不包含任何__new__,因此对此几乎无话可说。

但是您创建了一个元类,该元类在创建类A 时被实例化。换句话说,A 类本身就是一个对象,也是它的元类Singleton 的一个实例。

那么让我们看看会发生什么:

A 的环境完成后(它的方法存在,它的字典也存在,...),类被创建为元类的一个实例。本质上,调用是

A = Singleton('A', (object,), <the dict>)

其中&lt;the dict&gt; 是包含类名称空间的字典(此处为:__module____metaclass____init__)。

在对Singleton 的调用中,调用super(Singleton, self).__call__(*args, **kwargs) 会导致调用__new__ 方法,该方法返回一个新实例,然后在该实例上调用.__init__

这就是发生这种情况的原因:

calling __init__ of Singleton class <class '__main__.A'>
args:  ('A', (<type 'object'>,), '__module__': '__main__', '__metaclass__': <class '__main__.Singleton'>, '__init__': <function __init__ at 0x01F9F7B0>)
kwargs:  

A 构造完成后,通过实例化来使用它:

a = A(10)

这调用AASingleton 的一个实例,所以Singleton.__call__ 被调用——效果如下:

running __call__ of Singleton <class '__main__.A'>
args:  (10,)
kwargs:  

Singleton.__call__ 调用type.__call__,这调用A.__new__A.__init__

in __init__ of A:   <__main__.A object at 0x01FA7A10>
self.a:  10

那你就做

b = A(20)

调用Singleton.__call__:

running __call__ of Singleton <class '__main__.A'>
args:  (20,)
kwargs:  

这里super 调用被抑制并返回旧对象。

【讨论】:

如果我错了,请纠正我。在您的解释中:'On this call to Singleton, its __new__ is called and afterwards the .__init__ of the result.',通过单词 result,您是否指的是 Singleton 类的隐式 __new__ 方法的返回值(它将充当将创建类对象 A 的类) ? 还有,我的另一个问题是:你能举个例子,Singleton 类的__init__ 中的kwargs 包含 以外的任何内容吗? @GodMan 我已经改写了这句话。是的,Singleton.__call__ 调用A.__new__,它返回一个新实例,然后是新实例的__init__ 对于您的第二个问题:不,超类将始终使用位置参数调用,因此 kwargs 始终保持为空。您甚至可以将 *args 更改为 name, bases, dict,因为参数的数量也是固定的。 2 再次请求: 1. 对于Singleton.__call__ calls type.__call__, this calls A.__new__ and A.__init__ 行,您能否分别为A.__new__ 和A.__init__ 提供参数 2. 对于调用:b = A(20),您已经写了Here the super call is suppressed and the old object is returned.。是不是因为Singleton.__call__ 返回了A 的现有实例,所以这里没有调用A.__init__

以上是关于需要了解__init__、__new__和__call__的流程的主要内容,如果未能解决你的问题,请参考以下文章

Python:总是使用 __new__ 而不是 __init__?

__init__和__new__

使用 __new__ 覆盖子类中的 __init__

由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别

一个案例深入Python中的__new__和__init__

Python类中的__new__和__init__的区别