如何创建一个可以向类添加多个方法的类装饰器?

时间:2014-01-20 10:58:54

标签: python python-2.7 decorator python-decorators

我目前正在尝试实现一个类装饰器,它可以根据参数添加多个方法。例如:

@decorator('my_func')
class Screen:
    ...

将方法'my_func'(函数的主体在装饰器中定义)添加到测试类。

@decorator('my_func', 'my_func2')
class Screen:
   ...

将添加方法'my_func'和'my_func2'。到目前为止,我已成功完成以下任务:

def decorator(*args):
    def wrapper(cls):
        if not issubclass(cls, Screen):
            raise ValueError("You can't apply this decorator "
                             "on this class.")

        for arg in args:
            def clicker(self):
                return "Hey !" + arg
            setattr(cls, arg, clicker)
        return cls
    return wrapper

这里的问题是所有定义为'my_func'或'my_func2'的方法指向相同的代码,最后一个定义(在我的示例中为'my_func2'的代码)。 例如:

>>> Screen().my_func()
"Hey ! my_func2"
>>> Screen().my_func2()
"Hey ! my_func2"

我尝试了很多调整,例如使用FunctionType复制方法,使用MethodType绑定,结果始终保持不变。

但是这个代码在装饰器被链接时具有预期的行为:

@decorator('my_func')
@decorator('my_func2')
class Test:
    ...

我的目标是使用这个装饰器而不采用链接,当你有大量参数传递时可能会很蹩脚

欢迎任何想法!

1 个答案:

答案 0 :(得分:1)

感谢所提供的评论,我能够解决我的问题。正如@Martijn Pieters所描述的那样,问题来自于我正在为每个函数创建一个闭包而忽略'arg'的范围,因此它是绑定值的循环的迭代。通过传递'arg'作为参数,我现在可以在我的闭包的内部范围中传递我的参数:

def decorator(*args):
    def wrapper(cls):
        if not issubclass(cls, Screen):
            raise ValueError("You can't apply this decorator "
                             "on this class.")

        for arg in args:
            def clicker(self, marg=arg):
                return "Hey !" + marg
            setattr(cls, arg, clicker)
        return cls
    return wrapper