利用元类在python中创建singleton类



我在网上看到了一些关于如何利用python元类将类创建为Singleton的材料。代码片段大致如下:

class SingletonMetaClass(type):
_instance = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instance:
# usually a lock is used here, but omitted for simplicity
cls._instance[cls] = super().__call__(*args, **kwargs)
return cls._instance[cls]
class SingletonBaseClass(object, metaclass=SingletonMetaClass):
def __init__():
pass
class SingletonDerivedClass(SingletonBaseClass):
def __init__():
pass

上面的片段非常适合我——SingletonDerivedClass的所有实例都是相同的。然而,我发现奇怪的是,SingletonMetaClass中的行是cls._instance[cls] = super().__call__(*args, **kwargs)。显然,前者的cls指的是SingletonMetaClass本身,后者指的是子类,在这种情况下,它将是SingletonDerivedClass,但在__call__的签名中只有一个cls,python解释器如何判断哪个cls指的是什么?

如有任何回复,不胜感激!

cls的所有用法都没有引用元类。它们引用元类的实例SingletonBaseClassSingletonDerivedClass

clsSingletonBaseClass时查找cls._instance会找到SingletonMetaClass._instance,因为SingletonBaseClassSingletonMetaClass的实例,并且查找对象上的属性也会搜索其类,即使对象本身也是类。

"利用元类在python中创建singleton类">

不要。

求你了。

这定义了过度杀戮。

因此,在解释出了什么问题或您的疑问之前,以下是如何在Python中定义singleton,它只能是usd作为singleton,除非有人决定使用内省来";创建一个以上的单例"-在这一点上,这个人可能会滥用你现有的任何thr机制。

只需创建一个类,然后创建将成为您的单例实例。然后从命名空间中删除对该类的引用。如果有代码试图实例化应该是singleton的类,那么放置一个返回self:的__call__方法

class MySingleton():
...
def __call__(self):
return self
mysingleton = MySingleton()
del MySingleton

如果代码不希望实例化类,或者由于其他原因需要调用singleton:这个__call__只是装饰性的。实际上,singleton实例可以与类具有相同的名称,甚至不需要del语句。

现在,对于您在代码中感到困惑的部分:就元类中的任何方法而言,如果它是一个";实例";方法:即取";自我;作为第一个参数,第一个参数指的是一个类!(不是元类(。因此,在为元类编写方法时,我们通常将cls作为参数名称。

换句话说,在您的__call__的情况下;cls";是元类的实例:类本身。为__call__中的参数使用名称cls并不会神奇地使其接收到对编写该方法的类(元类本身(的引用。

如果给定您的类,您希望获得对元类的引用,只需像处理任何其他Python对象一样继续:使用type调用或检查__class__属性。

因此,如果你选择忽略我的建议,只为拥有一个singleton而拥有元类,那么你的代码的修复方法就是:

def __call__(cls, *args, **kwargs):
if cls not in cls._instance:
# usually a lock is used here, but omitted for simplicity
cls.__class__._instance[cls] = super().__call__(*args, **kwargs)
return cls._instance[cls]

如果您希望元类方法中的第一个参数是元类本身,@classmethod装饰器会这样做(但这种修饰符只能应用于普通方法,而不是"dunder"特殊方法,如__call__,该语言希望__call__和其他人将该实例作为第一个参数(

最新更新