我想在python中实现单例模式,我喜欢http://www.python-course.eu/python3_metaclasses.php中描述的模式。
<div class="my-wrap">
<div class="wrap-left">
<div class="wrap-one">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum voluptates ipsa tempora qui voluptas, dicta corrupti dolorum, iure esse earum ut pariatur, ad possimus facilis consequatur impedit accusantium autem! Nesciunt?</p>
</div>
<div class="wrap-two">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat commodi aspernatur et! Voluptates officiis nemo corporis delectus pariatur. Cupiditate perspiciatis illum minima, porro voluptas velit nobis ad eveniet modi explicabo.</p>
</div>
</div>
<div class="wrap-right">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perspiciatis reprehenderit, necessitatibus vel praesentium dolorum vitae sequi in magni voluptate alias fugit saepe eos sint dolore quae sapiente sunt itaque, cupiditate.</p>
</div>
</div>
代码完美无缺。但是,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__中,@staticmethod
方法在参数中有一个self。
如果我通过__call__()
或声明为self
或@staticmethod
,则代码无效。
有人可以解释@classmethod
方法背后语法的逻辑。
答案 0 :(得分:7)
命名方法cls
或self
的第一个参数只是一个约定。 __call__
方法 有cls
。那是因为对于元类,该方法绑定到一个类对象,名称反映了这一点。
同样的约定适用于@classmethod
方法;由于classmethod
对象的绑定方式的性质,第一个参数总是一个类,因此将第一个参数命名为cls
是有意义的。
但你可以自由地将第一个参数命名为其他任何东西。它不是使类方法或常规方法或方法在元类型上工作的名称。使用self
或cls
所做的就是记录这是什么类型的对象,使其他开发人员更容易在心理上跟踪正在发生的事情。
所以不,这不是一个隐式的类方法。第一个参数不绑定到Singleton
元类对象,它绑定到被调用的类。这是有道理的,因为该类对象是Singleton
元类型的实例。
如果您想深入了解绑定的工作原理(导致传递第一个参数的过程,无论名称如何),您可以阅读Descriptor HOWTO。 TLDR:函数,property
,classmethod
和staticmethod
对象都是描述符,并且每当您将它们作为支持对象(如实例或属性)上的属性进行访问时一个类,它们被绑定,经常导致一个不同的对象作为结果被返回,当被调用时,它将绑定对象传递给实际的函数。
答案 1 :(得分:0)
没有。但所有&#34;元类&#34;方法是隐含的&#34;类方法&#34;对于使用该元类的类。
当我们考虑到类只是元类的实例时,这是隐含的。从语言的角度来看,类的行为几乎与任何其他实例完全相同 - 以及与类中的任何交互都会触发对象中的dunder(__magic__
)方法 - 比如使用&#34; +, - , *,/&#34;运算符或使用[ ]
进行索引检索,或使用( )
调用它们会触发其类的相应方法。那通常是type
。
而且,正如另一个答案中所说,Python并不关心你在方法的第一个参数上使用什么名称。对于元类,在那里使用cls
是有意义的,因为&#34;实例&#34;处理的方法是元类。因为对于元类的第一个参数是有意义的。 __new__
方法名为metacls
(如下例所示)。因为新的&#34; cls&#34;是调用type.__new__
后得到的对象 - 纯Python中唯一可能实际创建类对象的调用。
class Meta(type):
def __new__(metacls, name, bases, namespace):
...
cls = super().__new__(metacls, name, bases, namespace)
...
return cls
(现在,仍然是关于问题的主题:__new__
是一个特例
一个隐式静态方法(即使对于不是元类的普通类) - Python专门添加第一个参数,使用与常规classmethod
不同的机制。这就是为什么上面的super().__new__
调用需要包含元数据作为第一个参数)