首页 > 解决方案 > 如何类装饰类方法

问题描述

我正在为继承 SuperClass 的子类 TestClass 使用类装饰器。我在 SuperClass 中有一个名为 what(cls) 的类方法,它接受一个类。我希望能够在我的子类 TestClass 中装饰该类,但它并没有像它所说的那样让我这样做。

TypeError: unbound method wrapper() must be called with TestClass instance as first argument (got nothing instead)

我试图对我的 TestClass 对象进行实例化,然后使用它来调用方法testclass.what(cls)并且它有效,但是当我这样做时TestClass.what(),它给了我上面的错误。

def class_decorator(cls):
    for attr_name in dir(cls):
        attr_value = getattr(cls, attr_name)
        if hasattr(attr_value, '__call__'):  # check if attr is a function
            # apply the function_decorator to your function
            # and replace the original one with your new one
            setattr(cls, attr_name, ball(attr_value))
    return cls


def ball(func):
    def wrapper(*args, **kwargs):
        print("hello")
        return func(*args, **kwargs)

    return wrapper



class SuperClass:
    def __init__(self):
        pass

    @classmethod
    def what(cls):
        print("testing")


@class_decorator
class TestClass(SuperClass):

    def what(cls):
        super().what()


TestClass.what()

预期的:

"hello"
"testing"
"hello"
"testing"

Actual: TypeError: unbound method wrapper() must be called with TestClass instance as first argument (got nothing instead)

标签: pythonpython-2.7classstaticpython-decorators

解决方案


您的程序存在一些问题;我将指出获得所需输出的方法,而不是详细介绍所有细节。

之所以会引发错误,是因为您已经覆盖了 中的类方法whatTestClass它现在接受一个cls可以是任何东西的参数。换句话说,您还需要使用classmethod装饰器在子类中装饰您的类方法。

如果要保留当前代码,则需要显式提供cls参数,如下所示:

from functools import partial

def class_decorator(cls): 
    for attr_name in vars(cls): 
        attr_value = getattr(cls, attr_name) 
        if callable(attr_value):  # check if attr is a function 
            if attr_name == 'what': 
                setattr(cls, attr_name, partial(ball(attr_value), cls=cls)) 
            else: 
                setattr(cls, attr_name, ball(attr_value)) 

使用partial将类作为第一个参数传递。

另外,我曾经在基础上vars(cls)获得cls.__dict__as dirdoes 递归(您不希望在这里)。此外,不要检查__call__属性,而是使用callable.


推荐阅读