需要了解__init __,__ new__和__call__的流程

God*_*Man 8 python singleton design-patterns metaclass

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)
Run Code Online (Sandbox Code Playgroud)

我从Ben对Python使用__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:  {}
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:  {}
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么argskwargs__init____call__变得不同.在使用元类时,这个链接(Python中的元类是什么?)已经解释了如何使用__new__和作为元类的函数.但是,我不明白如何__call__使用.

有人可以解释这个流程吗?通过这种方式,我的意思是,优先级,其中__new__,__call__,__init__被称为和谁通话呢?

glg*_*lgl 8

您的代码不包含任何内容__new__,因此可以说很少.

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

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

A环境完成后(它的方法存在,它的dict也存在,......),类被创建为元类的实例.从本质上讲,电话是

A = Singleton('A', (object,), <the dict>)
Run Code Online (Sandbox Code Playgroud)

<the dict>包含类的命名空间的dict 在哪里(这里:__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:  {}
Run Code Online (Sandbox Code Playgroud)

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

a = A(10)
Run Code Online (Sandbox Code Playgroud)

这叫A.A是一个实例Singleton,所以Singleton.__call__被调用 - 具有你看到的效果:

running __call__ of Singleton <class '__main__.A'>
args:  (10,)
kwargs:  {}
Run Code Online (Sandbox Code Playgroud)

Singleton.__call__电话type.__call__,这个电话A.__new__A.__init__:

in __init__ of A:   <__main__.A object at 0x01FA7A10>
self.a:  10
Run Code Online (Sandbox Code Playgroud)

然后你做

b = A(20)
Run Code Online (Sandbox Code Playgroud)

哪个叫Singleton.__call__:

running __call__ of Singleton <class '__main__.A'>
args:  (20,)
kwargs:  {}
Run Code Online (Sandbox Code Playgroud)

这里super调用被禁止并返回旧对象.