python - 清除元类单例

标签 python singleton metaclass

我已经使用 MetaClass 创建了一个 Singleton,如 Method 3 of this answer 中所述

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


class MySing(metaclass=Singleton): ...

我希望能够在 unittest.TestCasesetUp() 方法中清除 Singleton,以便每个测试都以一个干净的 Singleton 开始。

我想我真的不明白这个元类在做什么,因为我无法获得 clear() 方法的正确咒语:

     def clear(self):
       try:
          del(Singleton._instances[type(self)]
       except KeyError:
          pass   #Sometimes we clear before creating

对我在这里做错了什么有什么想法吗?我的单例没有被清除。

sing=MySing()
sing.clear()

上面的 type 调用返回 Singleton 而不是 MySing

最佳答案

让我们来看看 Singleton 的(更正的)定义和使用它定义的类。我正在用 Singleton 替换 cls 的使用,无论如何都会通过查找。

 class Singleton(type):
     _instances = {}
     
     # Each of the following functions use cls instead of self
     # to emphasize that although they are instance methods of
     # Singleton, they are also *class* methods of a class defined
     # with Singleton
     def __call__(cls, *args, **kwargs):
         if cls not in Singleton._instances:
             Singleton._instances[cls] = super().__call__(*args, **kwargs)
         return Singleton._instances[cls]

     def clear(cls):
         try:
             del Singleton._instances[cls]
         except KeyError:
             pass

class MySing(metaclass=Singleton):
    pass

s1 = MySing()   # First call: actually creates a new instance
s2 = MySing()   # Second call: returns the cached instance
assert s1 is s2 # Yup, they are the same
MySing.clear()  # Throw away the cached instance
s3 = MySing()   # Third call: no cached instance, so create one
assert s1 is not s3  # Yup, s3 is a distinct new instance

首先,_instances 是元类的类属性,用于将类映射到该类的唯一实例。

__call__ 是元类的实例方法;它的目的是使元类(即类)的实例可调用。 cls 这里是定义的类,不是元类。因此,每次调用 MyClass() 时,都会转换为 Singleton.__call__(MyClass)

clear 也是元类的实例方法,这意味着它也将元类的实例(即类)作为参数(不是用元类。)这意味着 MyClass.clear()Singleton.clear(MyClass) 相同。 (这也意味着您可以,但为了清楚起见,可能不应该编写 s1.clear()。)

元类实例方法与“常规”类类方法的标识也解释了为什么需要在元类中使用 __call__ 而在常规类中使用 __new__ class: __new__ 是一种特殊的类方法,无需对其进行修饰。元类为它的实例定义实例方法有点棘手,所以我们只使用__call__(因为type.__call__ 除了调用正确的 __new__ 方法外,没有做太多事情。

关于python - 清除元类单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50065276/

相关文章:

ios - 单例类为其 NSString 属性返回 nil 值

python - flake8 - E999 语法错误与 python3 元类参数

python - 如何在不显式导入的情况下使新装饰器在类中可用?

python - 是什么导致此 djcelery 错误 : NotRegistered?

python - binascii.Error : Incorrect padding in python django

Objective-C,需要帮助创建一个 AVAudioPlayer 单例

c++ - 如何强制单例类的使用风格

python - 如何使用 OpenCV 在图像上标记数字并绘制圆圈

python - pygame.event.get() 在线程内时不返回任何事件

inheritance - Groovy在这里做什么?