我有一些测试代码:
def num(num): def deco(func): def wrap(*args, **kwargs): inputed_num = num return func(*args, **kwargs) return wrap return deco @num(5) def test(a): return a + inputed_num print test(1)
运行此代码时,出现错误,显示'inputed_num'未已定义
我的问题是: 在wrap函数中,是否有一个闭包,func可以得到'inputed_num'?
无论如何,如果没有,我该如何实现目标:初始化一些值,并在主函数中直接使用此值。
思。
答案 0 :(得分:5)
我的问题是:在wrap函数中,是不是func可以得到'inputed_num'的闭包?
抱歉,这不是装饰工作的方式。在初始定义函数后,它们将被应用。到那时,为时已晚。
当你写:
@num(5)
def test(a):
return a + inputed_num
这相当于:
def test(a):
return a + inputed_num
test = num(5)(test) # note that num(5) is called after test() is defined.
要实现目标,请将inputed_num作为 test 的第一个参数。然后,让你的装饰师传入那个论点:
def num(num):
def deco(func):
def wrap(*args, **kwargs):
inputed_num = num
return func(inputed_num, *args, **kwargs) # this line changed
return wrap
return deco
@num(5)
def test(inputed_num, a): # this line changed
return a + inputed_num
@num(6)
def test2(inputed_num, a):
return a + inputed_num
print test(10) # outputs 15
print test2(10) # outputs 16
希望能为你清除一切: - )
答案 1 :(得分:5)
不,没有这样的封闭。函数可以关闭周围词汇上下文中存在的变量,而不是在调用上下文中。换句话说,如果您实际上在另一个函数中编写了一个函数,那么内部函数可以访问外部函数中的变量:
def f():
g = 2
def f2():
print g
f2()
但函数永远不能访问调用它们的函数内的变量。
一般来说,没有办法做你想做的事情,即在函数外部设置函数中的任意变量。最接近的是你可以在装饰器中使用global inputed_num
来将inputed_num
指定为全局变量。然后test
将访问全局值。
def num(num):
def deco(func):
def wrap(*args, **kwargs):
global outsider
outsider = num
return func(*args, **kwargs)
return wrap
return deco
@num(5)
def test(a):
print a+outsider
>>> test(2)
7
但是,当然变量设置是全局的,因此多个并发使用(例如,递归)将不起作用。 (只是为了好玩,你也可以看到here以一种非常神秘的方式来做到这一点,但是在现实世界的背景下它太疯狂了。)
答案 2 :(得分:2)
正如@Raymond所说 - 在定义函数后应用装饰器。这意味着在编译函数体本身时,Pythn会看到inputed_num
变量,并且当它捕获一个localy定义的变量时,它会生成代码以尝试将其作为全局变量访问它。
这意味着您可以在装饰器中解决它: 您的装饰器可以在函数globals()空间中设置具有所需名称的全局变量,然后调用该函数。它应该在单线程代码中可靠地工作:
def num(num):
def deco(func):
def wrap(*args, **kwargs):
glob = func.func_globals
marker = object()
original_value = glob.get("inputed_num", marker)
glob["inputed_num"] = num
result = func(*args, **kwargs)
if original_value is marker:
del glob["inputed_num"]
else:
glob["inputed_num"] = original_value
return result
return wrap
return deco
@num(5)
def test(a):
return a + inputed_num
和
>>> print test(1)
6
答案 3 :(得分:0)
这不是应该使用装饰器的方式,我认为你的目的可能是用这个
完成的def outwrapper(n):
def wrapper(func):
def f(*args, **argw):
return n + func(*args, **argw)
return f
return wrapper
@outwrapper(4)
def test(n):
return n
print test(1)