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)
我无法理解为什么args和kwargs为__init__和__call__变得不同.在使用元类时,这个链接(Python中的元类是什么?)已经解释了如何使用__new__和作为元类的函数.但是,我不明白如何__call__使用.
有人可以解释这个流程吗?通过这种方式,我的意思是,优先级,其中__new__,__call__,__init__被称为和谁通话呢?
您的代码不包含任何内容__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调用被禁止并返回旧对象.