Python 类外部的装饰器方法
你好,我想让默认的调用显示“nate在课堂上”。
我希望能把一个类的方法包裹起来,设置一个默认值,这样开发者就不需要再设置这个默认值了。
但是下面的代码给我报了错:
Traceback (most recent call last):
File "", line 18, in
File "", line 9, in rtn
UnboundLocalError: local variable 'var1' referenced before assignment
我已经尝试了大约一个小时,但就是无法让它正常工作。
这是代码:
class Bob(object):
def bob(self,var1='bob',var2=' is in the class'):
print var1,var2
def defalter(func):
def rtn(self=None,*args, **kwargs):
if not var1:
var1 = 'nate'
return rtn
b = Bob()
r = defalter(b.bob)
r()
2 个回答
1
你有几个误解。首先,你的装饰器是在被装饰的函数之前被调用的,所以它无法访问那个函数内部的局部变量。其次,即使它能访问这些变量,给它们赋新值也不会改变其他地方的变量。第三,装饰器需要负责调用底层的函数,如果它想这么做的话。你的装饰器从来没有调用底层的函数,所以它无法利用这个函数的行为。
这里有一种方法可以做到:
class Bob(object):
def bob(self,var1='bob',var2=' is in the class'):
print var1,var2
def defalter(func):
def rtn(var1='nate', *args, **kwargs):
func(var1, *args, **kwargs)
return rtn
>>> r = defalter(b.bob)
>>> r()
nate is in the class
我不太明白你为什么要在后面显式地进行装饰,而不是直接在类里面装饰这个方法。而且,如果用户给r
传递参数,你希望发生什么也不太清楚。我做的方式基本上就是把var1
的默认值替换成了“nate”。
1
这听起来像个坏主意,但下面的代码可以工作:
class Bob(object):
def bob(self,var1='bob',var2=' is in the class'):
print var1,var2
def defalter(func):
func.im_func.func_defaults = ('nate',) + func.im_func.func_defaults[1:]
return func
b = Bob()
r = defalter(b.bob)
r()
我很确定在python3.x中,属性名称是有变化的,不过我现在没什么动力去查具体改成什么了;如果你知道的话,可以随意编辑一下。
需要注意的是,这样做会改变所有的Bob
实例,而不仅仅是b
这个。如果你想要的效果不一定是这样的话,就要考虑清楚了……
如果你不想改变所有的Bob
实例,可以使用下面这个:
def defalter(func):
def new_func(var1='nate',**kwargs):
return func(var1=var1,**kwargs)
return new_func