我需要装饰一个对象的方法。它需要在运行时,因为应用于对象的装饰器取决于用户在调用程序时提供的参数(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
的结果。
答案 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)
“它需要在运行时,因为应用于对象的装饰器取决于用户在调用程序时提供的参数”
不要使用装饰器。装饰器只是对包装器的语法支持,你也可以使用普通的函数/方法调用。