利用元 class 在 python 中创建单例 class
Create singleton class in python by taking advantage of meta class
我在网上看到了一些关于如何利用 python metaclass 强制将 class 创建为 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
本身,而后者指的是子 class,在这种情况下,它将是 SingletonDerivedClass
,但内部 __call__
的签名只有一个cls
,python解释器如何判断哪个cls
指的是什么?
如有任何回复,我们将不胜感激!
None 的 cls
用法是指 metaclass。它们指的是 metaclass 的实例,SingletonBaseClass
或 SingletonDerivedClass
.
当 cls
是 SingletonBaseClass
时查找 cls._instance
找到 SingletonMetaClass._instance
因为 SingletonBaseClass
是 SingletonMetaClass
的实例,并查找属性在对象上也会搜索其 class,即使对象本身也是 class.
“利用元 class 在 python 中创建单例 class”
不要。
请。
这定义了矫枉过正。
所以,在解释哪里出了问题或你的疑问之前,这里是你如何在 Python 中定义一个单例,它只能作为一个单例使用,除非有人决定使用内省来“创建更多而不是一个单身人士”- 在这一点上,这个人也可以滥用你在那里拥有的任何机制。
只需创建一个 class,然后创建将成为您的单例的实例。然后从命名空间中删除对 class 的引用。
如果有代码会尝试实例化应该是单例的 class,请放置一个返回 self
:
的 __call__
方法
class MySingleton():
...
def __call__(self):
return self
mysingleton = MySingleton()
del MySingleton
如果代码不希望实例化 class,或者您出于其他原因需要单例可调用:此 __call__
只是装饰性的。实际上,单例实例可以与 class 同名,甚至不需要 del
语句。
现在,对于您在代码中感到困惑的部分:就元 class 中的任何方法而言,如果它是一个将是“实例”方法的方法:即采用“self” " 作为第一个参数,第一个参数指的是 class! (不是元class)。所以,我们在写metaclass.
的方法时,通常会写cls
作为参数名
换句话说,在您的 __call__
情况下,“cls”是元 class 的实例:classes 本身。在 __call__
中为参数使用名称 cls
并不能神奇地使其接收到对写入方法的 class 的引用(metaclass 本身)。
如果给定您的 class,您想要获得对元 class 的引用,只需像处理任何其他 Python 对象一样继续操作:使用 type
调用或检查 __class__
属性。
因此,如果您选择忽略我的建议,让元classes 只是为了拥有一个单例,那么您的代码的修复方法是:
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]
如果你想让 metaclass 方法中的第一个参数成为 metaclass 本身,@classmethod
装饰器会这样做(但这样的修饰符只能应用于普通方法 - 除了“dunder”特殊方法,如 __call__
- 语言期望 __call__
和其他人将实例作为第一个参数)
我在网上看到了一些关于如何利用 python metaclass 强制将 class 创建为 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
本身,而后者指的是子 class,在这种情况下,它将是 SingletonDerivedClass
,但内部 __call__
的签名只有一个cls
,python解释器如何判断哪个cls
指的是什么?
如有任何回复,我们将不胜感激!
None 的 cls
用法是指 metaclass。它们指的是 metaclass 的实例,SingletonBaseClass
或 SingletonDerivedClass
.
当 cls
是 SingletonBaseClass
时查找 cls._instance
找到 SingletonMetaClass._instance
因为 SingletonBaseClass
是 SingletonMetaClass
的实例,并查找属性在对象上也会搜索其 class,即使对象本身也是 class.
“利用元 class 在 python 中创建单例 class”
不要。
请。
这定义了矫枉过正。
所以,在解释哪里出了问题或你的疑问之前,这里是你如何在 Python 中定义一个单例,它只能作为一个单例使用,除非有人决定使用内省来“创建更多而不是一个单身人士”- 在这一点上,这个人也可以滥用你在那里拥有的任何机制。
只需创建一个 class,然后创建将成为您的单例的实例。然后从命名空间中删除对 class 的引用。
如果有代码会尝试实例化应该是单例的 class,请放置一个返回 self
:
__call__
方法
class MySingleton():
...
def __call__(self):
return self
mysingleton = MySingleton()
del MySingleton
如果代码不希望实例化 class,或者您出于其他原因需要单例可调用:此 __call__
只是装饰性的。实际上,单例实例可以与 class 同名,甚至不需要 del
语句。
现在,对于您在代码中感到困惑的部分:就元 class 中的任何方法而言,如果它是一个将是“实例”方法的方法:即采用“self” " 作为第一个参数,第一个参数指的是 class! (不是元class)。所以,我们在写metaclass.
的方法时,通常会写cls
作为参数名
换句话说,在您的 __call__
情况下,“cls”是元 class 的实例:classes 本身。在 __call__
中为参数使用名称 cls
并不能神奇地使其接收到对写入方法的 class 的引用(metaclass 本身)。
如果给定您的 class,您想要获得对元 class 的引用,只需像处理任何其他 Python 对象一样继续操作:使用 type
调用或检查 __class__
属性。
因此,如果您选择忽略我的建议,让元classes 只是为了拥有一个单例,那么您的代码的修复方法是:
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]
如果你想让 metaclass 方法中的第一个参数成为 metaclass 本身,@classmethod
装饰器会这样做(但这样的修饰符只能应用于普通方法 - 除了“dunder”特殊方法,如 __call__
- 语言期望 __call__
和其他人将实例作为第一个参数)