2012-10-31 87 views
1

我有以下装饰: 缺少参数

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?这更奇怪,因为timeoutretry参数仍然可以访问(尽管这是嵌套函数中的正常行为)。

有一种变通方法:

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

你如何使用'key'在装饰者? – ecatmur

回答

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

您将分配给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标记为局部变量的行为。