【问题标题】:Singleton class using metaclasses使用元类的单例类
【发布时间】:2017-05-26 10:05:52
【问题描述】:

以下是众所周知的创建单例元类的代码:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
            cls.x = 5
        return cls._instances[cls]


class MyClass(metaclass=Singleton):
    pass

m = MyClass()
v = MyClass()
print (m.x)
m.x = 420
print (v.x)

我的问题是为什么我们需要再次使用类型类的调用函数来初始化类?为什么我们不能像普通的类初始化一样调用 init 方法。像这样的:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = cls(*args, **kwargs)
            cls.x = 5
        return cls._instances[cls]


class MyClass(metaclass=Singleton):
    pass

m = MyClass()
v = MyClass()
print (m.x)
m.x = 420
print (v.x)

这无论如何都会进入一个无限循环。

【问题讨论】:

    标签: python singleton


    【解决方案1】:

    因为试图通过调用它来创建一个类的实例,就像你在cls._instances[cls] = cls(*args, **kwargs) 行中所做的那样,它本身会调用元类__call__,这是你尝试调用的确切方法as is explained here

    现在,如果有一件事,你不应该仅仅为了创建单例而使用元类。

    Python 中的元类机制很复杂——你在这个问题上遇到的问题表明你现在掌握了超类上的简单继承和方法调用是如何工作的——而元类比这复杂一个数量级。

    而且,除了复杂之外,具有自定义元类的类通常不能与具有自定义元类的其他类组合,因此一般规则是尽量减少它们的使用。

    如何创建单例类:

    但是要创建一个单例,您可以将所有检查放在类普通的__new__ 方法中。无需使用元类——只需简单的类继承:

    _instances = {}
    
    class Singleton(object):
    
       def __new__(cls, *args, **kw):
          if not cls in _instances:
              instance = super().__new__(cls)
              _instances[cls] = instance
    
          return _instances[cls]
    

    然后从这个继承你的单例类。

    【讨论】:

      猜你喜欢
      • 2014-08-05
      • 2014-03-01
      • 2011-10-17
      • 1970-01-01
      • 2017-04-30
      • 2021-08-02
      • 2016-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多