在python中创建单例类

时间:2016-04-05 16:30:20

标签: python

我正在阅读http://blog.thedigitalcatonline.com/blog/2014/09/01/python-3-oop-part-5-metaclasses/#.VwPSjDG1XGD。在其中,他们有:

class Singleton(type):
    instance = None
    def __call__(cls, *args, **kw):
        if not cls.instance:
             cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

解释是:

  

我们正在定义一个新类型,它继承自类型以提供Python类的所有花俏。我们覆盖调用方法,这是我们调用类时调用的特殊方法,即我们实例化时。新方法通过仅在未设置实例属性时调用它来包装原始类型方法,即第一次实例化类,否则它只返回记录的实例。正如您所看到的,这是一个非常基本的缓存类,唯一的技巧是它应用于实例的创建。

我不确定我理解这一行:

cls.instance = super(Singleton, cls).__call__(*args, **kw)

有人能以另一种方式解释这里发生的事情吗?

1 个答案:

答案 0 :(得分:3)

默认情况下,__call__类对象会生成此类的实例(请记住,类是函数之类的callables,与PHP之类的其他语言相比,它们在接口中是完全独立的怪物)。此实例将存储在cls.instance

cls.instance = super(Singleton, cls).__call__(*args, **kw)

通过包装前一个条件,如果instance已经是...实例,则返回它。这意味着:类__new__之类的东西不会再次在类上调用,而__init__之类的东西不会再次在实例上调用,而只是返回旧的 - 已存在的实例。

注意:在默认实现中调用__call__时,会为类调用__new__方法(它始终是类方法;您永远不会使用@ classmethod decorator那里)创建实例。之后,__init__消息将发送到实例以进行初始化。

关于元类的注释:请记住,Singleton不是通常的类,而是Metaclass。它不是您将继承的类,而是您将使用。(/ p>)实例化您的类的元类

对象是类的实例,而类是元类的实例(由于它们也是类,可能会使您感到困惑)。这意味着存在一个闭环,其中引用type是其自身的实例:

assert isinstance(type, type)

在那里,您的代码将是这样的:

class MySingletonClass(object):
    __metaclass__ = Singleton

魔法将开始:

  1. 您在代码上覆盖的__call__方法将在类上执行,因为它是在元类(Singleton)上定义的。这意味着:

    i = MySingletonClass() # Executes what is defined in Singleton as __call__
    

    你不应该混淆这个:

    i() # Will crash if MySingletonClass does not define __call__ for its instances.
    
  2. 您在代码中进行的调用还有另一个等价物:

    super(Singleton, cls).__call__(*a, **kwa)
    

    与:

    相同
    (a type isntance)(*a, **kwa)
    

    或者

    (a type isntance).__call__(*a, **kwa)
    

    每个类都有相同的行为,不使用像你这样的自定义元类,用于创建实例。

相关问题