我有一个以下的装饰者:
from decorator import decorator
def my_decorator(key=None, timeout=None, retry=0):
"""
My decorator
"""
import pdb; pdb.set_trace()
def _my_decorator(func):
import pdb; pdb.set_trace()
key = key or func.__name__
@decorator
def __my_decorator(f, *args, **kwargs):
result = "abc"
return result
return __my_decorator(func)
return _my_decorator
在第一个pdb部分中,locals()
的结果是:
>>> locals()
{'key': None, 'retry': 0, 'pdb': <module 'pdb' from '/opt/python/2.7/lib/python2.7/pdb.pyc'>, 'timeout': None}
在第二个pdb部分中,locals()
的结果是:
>>> locals()
{'timeout': None, 'retry': 0, 'pdb': <module 'pdb' from '/opt/python/2.7/lib/python2.7/pdb.pyc'>, 'func': <function get_items at 0x9e172cc>}
没有pdb的异常:
key = key or func.__name__
UnboundLocalError: local variable 'key' referenced before assignment
你知道为什么key
参数在嵌套函数_my_decorator中消失了吗?这更奇怪,因为timeout
和retry
参数仍然可访问(尽管这是嵌套函数中的正常行为)。
有一种解决方法:
def my_decorator(key=None, timeout=None, retry=0):
"""
My decorator
"""
key2 = key
def _my_decorator(func):
key = key2 or func.__name__
...
但它不是解决方案(key
中的参数_my_decorator
仍在消失,但现在可以访问key2
Python版本:2.7.3
答案 0 :(得分:4)
如果在内部作用域中绑定变量名,则它将从外部作用域的闭包中省略。这是因为否则后续代码将不知道引用哪个绑定:
def outer(x=None):
def inner(y=0):
if y:
x = y
return x # outer.x or inner.x?
修复方法是重命名变量,使它们不影响封闭范围:
def my_decorator(key=None, timeout=None, retry=0):
def _my_decorator(func):
func_key = key or func.__name__
...
答案 1 :(得分:1)
您正在将分配给 key
,这会使该变量成为本地变量。使用Python 2无法实现您想要实现的目标(在Python 3中,您可以将其标记为nonlocal
)。
解决方法是使key
变为可变,然后改变它的内容而不是分配给它:
from decorator import decorator
def my_decorator(key=None, timeout=None, retry=0):
"""
My decorator
"""
key = [key]
def _my_decorator(func):
key[0] = key[0] or func.__name__
现在我们变异 key
,而不是分配给变量。换句话说,我们正在执行道德等同于key.__setitem__(0, key[0] or func.__name__)
,而你的代码正在执行locals()['key'] = key or func.__name
,这是一种将key
标记为局部变量的行为。