如何在Python中将类实例变量作为方法装饰器的参数?
我想知道在Python中,如何把一个类的实例变量当作方法装饰器的参数来用。下面是一个简单的例子,展示了我想做的事情。显然,这样做是失败的,因为装饰器函数无法访问到实例的引用,我不知道该如何从装饰器中获取这个引用。
def decorator1(arg1):
def wrapper(function):
print "decorator argument: %s" % arg1
return function
return wrapper
class Foo(object):
def __init__(self, arg1):
self.var1 = arg1
@decorator1(self.var1)
def method1(self):
print "method1"
foo = Foo("abc")
foo.method1()
6 个回答
1
这是我们以前是怎么做的。
class Foo(object):
def __init__(self, arg1):
self.var1 = arg1
def method1(self):
self.lock()
try:
self.do_method1()
except Exception:
pass # Might want to log this
finally:
self.unlock()
def do_method1(self):
print "method1"
def lock(self):
print "locking: %s" % self.arg1
def unlock(self):
print "unlocking: %s" % self.arg1
现在,一个子类只需要重写 do_method1
就能享受到“包装”的好处。这样做是老办法,没有用到任何 with
语句。
是的,这样写比较啰嗦。不过,它也没有什么神秘的地方。
9
你的“warper”函数其实是一个装饰器,而不是一个真正的“warper”。你的“decorator1”函数是一个装饰器的构造函数。如果你想在运行时访问self.var1,你需要做一个warper,而不是装饰器:
def decorator(function):
def wrapper(self,*args,**kwargs):
print "Doing something with self.var1==%s" % self.var1
return function(self,*args,**kwargs)
return wrapper
class Foo(object):
def __init__(self, arg1):
self.var1 = arg1
@decorator
def method1(self):
print "method1"
foo = Foo("abc")
foo.method1()
如果你想要一个更通用的装饰器,最好是声明一个可调用的类:
class decorator:
def __init__(self,varname):
self.varname = varname
def __call__(self,function):
varname=self.varname
def wrapper(self,*args,**kwargs):
print "Doing something with self.%s==%s" % (varname,getattr(self,varname))
return function(self,*args,**kwargs)
return wrapper
使用:
@decorator("var1")
11
这段话的意思是,装饰器在创建类的时候就会被调用,这个时间点是在实例被创建之前(如果有创建的话)。所以如果你的“装饰器”需要用到实例,那你就得在实例创建的时候进行“装饰”。
def get_decorator(arg1):
def my_decorator(function):
print "get_decorator argument: %s" % arg1
return function
return my_decorator
class Foo(object):
def __init__(self, arg1):
self.var1 = arg1
self.method1 = get_decorator(self.var1)(self.method1)
def method1(self):
print "method1"
foo = Foo("abc")
foo.method1()
另外,我把函数的名字改成了更符合它们意思的名称;在你的例子中,真正的“装饰器”,也就是那个可能会修改方法的函数,其实是 wrapper
,而不是 decorator1
。