13
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 使用 __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:  {}

我无法理解argsandkwargs是如何变得不同的__init____call__在使用元类时,这个链接(What is a metaclass in Python?)解释了如何使用__new__元类和函数。但是,我不明白__call__是如何使用的。

有人可以解释一下流程吗?我的意思是,调用 , 和谁调用它们的__new__优先__call____init__

4

1 回答 1

12

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

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

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

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

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

<the 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:  {}

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

a = A(10)

这调用A. A是 的一个实例Singleton,因此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调用被抑制并返回旧对象。

于 2012-10-19T10:09:14.990 回答