2012-10-31 209 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標記爲局部變量的行爲。