我想用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
或{
但是,在Python数据模型https://docs.python.org/3/reference/datamodel.html#object.__call__中,__call__()
方法的参数中有一个self。在
如果我传递self
,或者声明为@staticmethod
或{
有人能解释一下__call__()
方法背后的语法逻辑吗。在
马丁的回答说明了一切。我加上这一点,也许不同的措辞可以给不同的人带来更多的启示:
Python调用()这是一个隐式类方法吗?在
不是。但是所有的“元类”方法都是使用该元类的类的隐式“类方法”。在
当我们考虑到类只是元类的实例时,这是隐含的。从语言的角度来看,一个类的行为与任何其他实例几乎完全相同,而且与一个类的任何交互都会触发对象中的dunder(}。在
__magic__
)方法,比如使用“+,-,*,/”运算符,或使用[ ]
进行索引检索,或者用( )
调用它们,都会触发其类上相应的方法。通常是{而且,正如另一个答案所说的,Python不关心在方法的第一个参数上使用什么名称。对于元类,使用
cls
是有意义的,因为方法处理的“实例”是元类。元类__new__
方法的第一个参数命名为metacls
(如下面的示例所示)。因为新的“cls”是我们在调用type.__new__
后得到的对象,这是纯Python中唯一可能实际创建类对象的调用。在(现在,仍然是关于这个问题的主题:
__new__
是一个特例吗 对于一个隐式静态方法(即使对于不打算成为元类的普通类也是如此),Python特别向其添加第一个参数,使用的机制与对正则的classmethod
s所做的不同。这就是为什么上面的super().__new__
调用需要将metals作为第一个参数包含在内)将方法的第一个参数命名为
cls
或self
只是一个约定。__call__
方法没有自变量,只是在这里它的名称是的cls
。这是因为对于元类,方法是绑定到类对象的,其名称反映了这一点。在同样的约定也适用于
@classmethod
方法;第一个参数总是一个类,这是由于classmethod
对象是如何绑定的,因此将第一个参数命名为cls
是有意义的。在但你可以随意给第一个论点起其他名字。它不是使类方法、常规方法或元类型上的方法工作的名称。使用
self
或cls
所做的就是记录这是什么类型的对象,这样其他开发人员就更容易在心里跟踪正在发生的事情。在所以不,这不是一个隐式类方法。第一个参数没有绑定到
Singleton
元类对象,而是绑定到被调用的类。这是有意义的,因为类对象是Singleton
元类型的一个实例。在如果您想深入研究绑定的工作原理(不管名称是什么,都可以传入第一个参数的过程),您可以阅读Descriptor HOWTO。TLDR:functions、
property
、classmethod
和staticmethod
对象都是描述符,每当您将它们作为支持对象(如实例或类)的属性访问时,它们都是绑定的,通常会导致返回一个不同的对象,当调用时,这些对象会将绑定对象传递给实际函数。在相关问题 更多 >
编程相关推荐