无法向classmethods添加属性

时间:2013-11-20 03:51:02

标签: python

以下代码段会导致AttributeError: 'classmethod' object has no attribute 'val'。知道为什么以及如何解决这个问题?

class App(object):
    @classmethod
    def cfn(kls, *args):
        print kls, args
    cfn.val = 10

2 个答案:

答案 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

它将按预期工作