如何装饰对象方法?

时间:2011-05-10 13:17:57

标签: python python-3.x runtime decorator

我需要装饰一个对象的方法。它需要在运行时,因为应用于对象的装饰器取决于用户在调用程序时提供的参数(argv提供的参数),因此同一个对象可以装饰3次,2次或不装饰所有

这里有一些上下文,该程序是一个拼图求解器,主要的行为是自动找到解谜的解决方案,我自动意思是没有用户干预。这里是装饰起作用的地方,我想要的其中一个是绘制执行过程中发生的事情的图表,但我只想在使用标志--draw-graph时才这样做。

这是我尝试过的:

class GraphDecorator(object):
    def __init__(self, wrappee):
        self.wrappee = wrappee
    def method(self):
        # do my stuff here
        self.wrappee.method()
        # do more of stuff here
    def __getattr__(self,attr):
        return getattr(self.wrappee,attr)

为什么它不起作用: 由于我构建应用程序的方式不起作用,当我的Decorator类中不存在的方法被调用时,它感觉回到了装饰类的实现,问题是应用程序总是开始调用方法{{ 1}}不需要装饰,所以使用了未修饰的后退,并且从未装饰的形式内部它总是称为未修饰的方法,我需要的是从对象替换方法,而不是代理它:

run

这是我的问题,由于参数的数量错误,在调用时,装饰的表单不会收到# method responsible to replace the undecorated form by the decorated one def graphDecorator(obj): old_method = obj.method def method(self): # do my stuff here old_method() # do more of my stuff setattr(obj,'method',method) # replace with the decorated form 的结果。

4 个答案:

答案 0 :(得分:1)

问题在于我无法使用func(self)作为方法。原因是setattr()方法没有绑定函数,并且函数就像静态方法 - 而不是类方法 - ,由于python的内省特性,我能够提出这个解决方案:

def decorator(obj):
    old_func = obj.func # can't call 'by name' because of recursion

    def decorated_func(self):
        # do my stuff here
        old_func() # does not need pass obj
        # do some othere stuff here

    # here is the magic, this get the type of a 'normal method' of a class
    method = type(obj.func)

    # this bounds the method to the object, so self is passed by default 
    obj.func = method(decorated_func, obj)

我认为这是在运行时装饰对象方法的最佳方法,尽管找到一种直接调用method()的方法很不错,没有行method = type(obj.func)

答案 1 :(得分:0)

您可能希望使用__getattribute__而不是__getattr__(后者仅在“标准”查找失败时才会被调用):

class GraphDecorator(object):
    def __init__(self, wrappee):
        self.__wrappee = wrappee

    def method(self):
        # do my stuff here
        self.wrappe.method()
        # do more of stuff here

    def __getattribute__(self, name):
        try:
            wrappee = object.__getattribute__(self, "_GraphDecorator__wrappee")
            return getattr(wrappee, name)
        except AttributeError:
            return object.__getattribute__(self, name)

答案 2 :(得分:0)

  

我需要装饰一个对象的方法。它需要在运行时,因为应用于对象的装饰器取决于用户在调用程序时提供的参数(argv提供的参数),因此同一个对象可以装饰3次,2次或不装饰所有

不幸的是,上述情况不正确,您要做的事情是不必要的。 你可以在运行时这样做。例如:

import sys
args = sys.argv[1:]

class MyClass(object):
    pass

if args[0]=='--decorateWithFoo':
    MyClass = decoratorFoo(MyClass)
if args[1]=='--decorateWithBar'
    MyClass = decoratorBar(MyClass)

语法:

@deco
define something

与以下内容相同:

define something
something = deco(something)

您还可以制作装饰工厂@makeDecorator(command_line_arguments)

答案 3 :(得分:0)

“它需要在运行时,因为应用于对象的装饰器取决于用户在调用程序时提供的参数”

不要使用装饰器。装饰器只是对包装器的语法支持,你也可以使用普通的函数/方法调用。