以下代码段会导致AttributeError: 'classmethod' object has no attribute 'val'
。知道为什么以及如何解决这个问题?
class App(object):
@classmethod
def cfn(kls, *args):
print kls, args
cfn.val = 10
答案 0 :(得分:0)
类方法根本不支持向它们添加任意属性。最好的办法是将您要放入类别方法属性的数据带到其他地方。
答案 1 :(得分:0)
实际上可以为您的classmethod添加自定义属性。
NB仅在Python 3.4上测试
<强> TL; DR 强>
class classmethod_with_custom_attribute(object):
def __init__(self, val):
self.val = val
def __call__(self, func):
def wrapped_func(*args, **kwargs):
return func(*args, **kwargs)
wrapped_func.val = self.val
wrapped_func = classmethod(wrapped_func)
return wrapped_func
class App(object):
@classmethod_with_custom_attribute(val=10)
def cfn(cls, *args):
print(cls, args)
<强>解释强>
首先,您必须了解装饰器的工作原理,因为classmethod是装饰器。
写作
@classmethod
def cfn(cls, *args):
print(cls, *args)
实际上和写
相同def cfn(cls, *args):
print(cls, *args)
cfn = classmethod(cfn)
现在,如果您尝试向方法添加属性,请不要将其写为
@classmethod
def cfn(cls, *args):
print(cls, *args)
cfn.val = 10
因为它相当于
def cfn(cls, *args):
print(cls, *args)
cfn = classmethod(cfn)
cfn.val = 10
所以你要将属性添加到decorator返回的方法,而不是你的实际方法。简单的解决方案是将属性添加到方法中,然后 装饰它:
def cfn(cls, *args):
print(cls, *args)
cfn.val = 10
cfn = classmethod(cfn)
这样你就可以装饰已附加属性的方法,显然decorator会返回相同的方法对象,因此你不会丢失属性。 我们都同意这种语法不是很好并且难以阅读。保持装饰器语法要好得多。您可以将所有逻辑放在自定义装饰器中,如下所示:
class classmethod_with_custom_attribute(object):
def __init__(self, val):
self.val = val
def __call__(self, func):
def wrapped_func(*args, **kwargs):
return func(*args, **kwargs)
wrapped_func.val = self.val
wrapped_func = classmethod(wrapped_func)
return wrapped_func
在这里我们也这样做,请注意在 classmethod装饰器调用之前分配自定义属性的部分。现在我们可以像这样使用装饰器:
@classmethod_with_custom_attribute(val=10)
def cfn(cls, *args):
print(cls, args)
现在你可以打电话了
App.cfn.val
它将按预期工作