[免责声明:可能有更多的Python方式来做我想做的事情,但我想知道Python的作用域在这里是如何工作的]
我正在尝试找到一种方法来制作一个装饰器,该装饰器可以执行诸如将名称注入另一个函数的作用域之类的操作(这样该名称就不会泄漏到装饰器的作用域之外)。例如,如果我有一个函数说要打印名为的变量var
尚未定义,我想在调用它的装饰器中定义它。这是一个失败的例子:
c = 'Message'
def decorator_factory(value):
def msg_decorator(f):
def inner_dec(*args, **kwargs):
var = value
res = f(*args, **kwargs)
return res
return inner_dec
return msg_decorator
@decorator_factory(c)
def msg_printer():
print var
msg_printer()
我想要打印“Message
”,但它给出了:
NameError: global name 'var' is not defined
回溯甚至指向哪里var
被定义为:
<ipython-input-25-34b84bee70dc> in inner_dec(*args, **kwargs)
8 def inner_dec(*args, **kwargs):
9 var = value
---> 10 res = f(*args, **kwargs)
11 return res
12 return inner_dec
所以我不明白为什么找不到var
.
有什么办法可以做这样的事情吗?
你不能。作用域名称(闭包)是在编译时确定的,您不能在运行时添加更多名称。
您最希望实现的目标就是添加global名称,使用函数的own全局命名空间:
def decorator_factory(value):
def msg_decorator(f):
def inner_dec(*args, **kwargs):
g = f.__globals__ # use f.func_globals for py < 2.6
sentinel = object()
oldvalue = g.get('var', sentinel)
g['var'] = value
try:
res = f(*args, **kwargs)
finally:
if oldvalue is sentinel:
del g['var']
else:
g['var'] = oldvalue
return res
return inner_dec
return msg_decorator
f.__globals__
是包装函数的全局命名空间,因此即使装饰器位于不同的模块中,它也能工作。如果var
已经定义为全局变量,它被替换为新值,并且在调用该函数后,全局变量被恢复。
这是有效的,因为函数中任何未分配给且未在周围范围中找到的名称都会被标记为全局名称。
Demo:
>>> c = 'Message'
>>> @decorator_factory(c)
... def msg_printer():
... print var
...
>>> msg_printer()
Message
>>> 'var' in globals()
False
但除了装饰之外,我还可以定义var
在全球范围内directly.
请注意,更改全局变量不是线程安全的,并且对同一模块中其他函数的任何瞬时调用也仍然会看到相同的全局变量。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)