这次对 a.f 的调用实际上要求 f (通过descriptorprotocol)对象真正返回 . 然后在没有参数的情况下调用此对象,并将调用偏转到实际 f ,在前面添加 a .
那么 a.f() 真正做的是用 (a) 作为参数调用原始的 f 函数 .
为了防止这种情况,我们可以包装该函数
带有 @staticmethod 装饰的
, 带有 @classmethod 装饰的
,
与其他一个类似的工作,自制装饰器 .
@staticmethod 将其转换为一个对象,当被询问时,它会更改参数传递行为,以便它与调用原始 f 的意图相匹配:
class A(object):
def method(self):
pass
@staticmethod
def stmethod():
pass
@classmethod
def clmethod(cls):
pass
a = A()
a.method() # the "function inside" gets told about a
A.method() # doesn't work because there is no reference to the needed object
a.clmethod() # the "function inside" gets told about a's class, A
A.clmethod() # works as well, because we only need the classgets told about a's class, A
a.stmethod() # the "function inside" gets told nothing about anything
A.stmethod() # works as well
3 回答
假设您有一个类
Car
,它代表系统中的Car
实体 .classmethod
是一个适用于Car
类的方法,不适用于任何Car
的实例之一 . 用@classmethod
装饰的函数的第一个参数,通常称为cls
,因此是类本身 . 例:函数作用于类的特定实例;通常称为
self
的第一个参数是实例本身:总结一下:
classmethod
来实现适用于整个类(而不是特定类实例)的方法:如果在类中定义方法,则以特殊方式处理它:对它的访问将其包装在一个特殊对象中,该对象修改调用参数以包含
self
,即对引用对象的引用:这次对
a.f
的调用实际上要求f
(通过descriptor protocol)对象真正返回 . 然后在没有参数的情况下调用此对象,并将调用偏转到实际f
,在前面添加a
.那么
a.f()
真正做的是用(a)
作为参数调用原始的f
函数 .为了防止这种情况,我们可以包装该函数
带有
@staticmethod
装饰的,
带有
@classmethod
装饰的,
与其他一个类似的工作,自制装饰器 .
@staticmethod
将其转换为一个对象,当被询问时,它会更改参数传递行为,以便它与调用原始f
的意图相匹配:所以
@classmethod
和@staticmethod
有一个共同点,就是他们被召唤的具体对象;区别在于@staticmethod
根本不想知道任何事情,而@classmethod
想知道它的类 .所以后者获取类对象所使用的对象是一个实例 . 在这种情况下,只需将
self
替换为cls
即可 .现在,何时使用什么?
嗯,这很容易处理:
如果您有权访问
self
,则显然需要实例方法 .如果您不访问
self
,但想了解其类,请使用@classmethod
. 例如,这可以是工厂方法的情况 .datetime.datetime.now()
就是这样一个例子:您可以通过其类或实例调用它,但它会创建一个具有完全不同数据的新实例 . 我甚至使用它们一次来自动生成给定类的子类 .如果既不需要
self
也不需要cls
,则使用@staticmethod
. 如果他们不需要关心子类化,这也可以用于工厂方法 .@classmethod
将类作为第一个参数,而function接受类的实例我故意在
meth
中使用了self
参数,因此它与func
的语法非常接近 . 但通常你最好使用cls
作为参数: