关于将classmethod
和property
组合在一起的问题已得到解答:Using property() on classmethods
我还是不明白问题的原因,请帮忙。
我对classmethod
的理解是,它只是将self
替换为cls
。考虑到这一点,在过去几年中,我编写了几种分类方法,现在我发现我一直都错了。
那么下面的代码@classmethod
和@cm
有什么区别?
def cm(func):
def decorated(self, *args, **kwargs):
return func(self.__class__, *args, **kwargs)
return decorated
class C:
V = 0
@property
@classmethod
def inc1(cls):
cls.V += 1
print("V1 =", cls.V)
@property
@cm
def inc3(cls):
cls.V += 3
print("V3 =", cls.V)
c = C()
#c.inc1 # fails with: TypeError: 'classmethod' object is not callable
c.inc3 # works
带有
inc3
的cm
有效,但是带有inc1
的classmethod
无效。 最佳答案
下面的代码中@classmethod和@cm有什么区别?
装饰器在创建实例之前的类创建期间调用。
在您的情况下,由于@cm返回依赖于func(self.__class__, *args, **kwargs)
的self
,因此应将其用作实例方法。
另一方面,@ classmethod可以在创建实例之前使用。
def cm(func):
def decorated(self, *args, **kwargs):
return func(self.__class__, *args, **kwargs)
return decorated
class C:
@classmethod
def inc1(cls):
(blablabla)
@cm
def inc3(cls):
(blablabla)
C().inc1() # works as a instance method
C.inc1() # works as a classmethod
C().inc3() # works as a instance method
C.inc3() # TypeError: unbound method decorated() must be called with C instance as first argument (got nothing instead)
对于类方法和属性的组合,可以通过返回一个自定义对象来完成。 Reference
class ClassPropertyDescriptor(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
return self.f.__get__(obj, klass)()
def classproperty(func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
return ClassPropertyDescriptor(func)
class C:
@classproperty
def inc1(cls):
(blablabla)
C.inc1 # works as a classmethod property
[编辑]
问:classmethod()调用对其装饰的方法有什么作用?
可以通过使用descriptor来实现
class ClassMethodDescriptor(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
def newfunc(*args):
return self.f(klass, *args)
return newfunc
def myclassmethod(func):
return ClassMethodDescriptor(func)
class C:
@myclassmethod
def inc1(cls):
(blablabla)
C.inc1() # works as a classmethod
问:为什么结果不可调用?
因为
ClassMethodDescriptor
的实现未定义__call__
函数。一旦使用@property
,它将返回无法调用的ClassMethodDescriptor。关于python - 除将自己更改为cls之外,classmethod还做什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40593183/