我想在 python 中实现单例模式,我喜欢 http://www.python-course.eu/python3_metaclasses.php 中描述的模式.
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 SingletonClass(metaclass=Singleton):
pass
class RegularClass():
pass
x = SingletonClass()
y = SingletonClass()
print(x == y)
x = RegularClass()
y = RegularClass()
print(x == y)
并且代码运行完美。但是,__call__()
没有 self
,也没有 @classmethod
或 @staticmethod
声明。
但是,在 Python 数据模型中 https://docs.python.org/3/reference/datamodel.html#object.__call__ __call__()
方法在参数中有一个 self。
如果我传递 self
,或者声明为 @staticmethod
或 @classmethod
,代码将不起作用。
谁能解释一下 __call__()
方法背后的语法逻辑。
最佳答案
将方法的第一个参数命名为 cls
或 self
只是一种约定。 __call__
方法确实 有一个 self 参数,只是它在这里被命名 cls
。那是因为对于元类,方法绑定(bind)到类对象,名称反射(reflect)了这一点。
相同的约定适用于@classmethod
方法;由于 classmethod
对象的绑定(bind)方式的性质,第一个参数始终是一个类,因此将第一个参数命名为 cls
是有意义的。
但是您可以随意为第一个参数命名。使类方法或常规方法或元类型上的方法起作用的不是名称。使用 self
或 cls
所做的只是记录这是什么类型的对象,让其他开发人员更容易在脑海中跟踪正在发生的事情.
所以不,这不是隐式类方法。第一个参数未绑定(bind)到 Singleton
元类对象,它绑定(bind)到被调用的类。这是有道理的,因为该类对象是 Singleton
元类型的一个实例。
如果您想深入了解绑定(bind) 的工作原理(导致传入第一个参数的过程,无论名称如何),您可以阅读 Descriptor HOWTO . TLDR:函数、property
、classmethod
和 staticmethod
对象都是描述符,无论何时您将它们作为属性访问在支持对象(例如实例或类)上,它们是绑定(bind)的,通常会导致返回一个不同对象作为结果,在调用时将绑定(bind)对象传递给实际函数。 p>
关于Python __call__() 这是一个隐式类方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44704461/