我使用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): ...
我希望能够在setUp()
的{{1}}方法中清除Singleton,以便每个测试都以一个干净的Singleton开始。
我想我真的不明白这个metaClass正在做什么,因为我无法获得unittest.TestCase
方法的正确咒语:
clear()
对我在这里做错了什么的想法?我的单身人士没有被清除。
def clear(self):
try:
del(Singleton._instances[type(self)]
except KeyError:
pass #Sometimes we clear before creating
上面的sing=MySing()
sing.clear()
调用会返回type
而不是Singleton
。
答案 0 :(得分:2)
让我们来看看Singleton
的一个(更正的)定义和一个使用它定义的类。我正在将cls
的使用替换为Singleton
,无论如何都会在其中传递查询。
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:
continue
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__
:{{1}作为一个类方法是特殊的,而不必像这样装饰它。元类为其实例定义实例方法有点棘手,所以我们只使用__new__
(因为__call__
没有做太多,如果有的话,除了调用正确的type.__call__
方法之外)。
答案 1 :(得分:-1)
我乍一看这个元类有三个有用的测试用例。
所有这些测试都可以在没有“重置”按钮的情况下实现。在此之后,您将涵盖大部分基础。 (我可能已经忘记了一个)。
只需创建一些使用此元类的不同TestClasses并检查其Id和类型。