2013-09-21 72 views
0

我已經爲Flask用戶權限系統編寫了一個修飾器函數。當我嘗試點擊裝飾的視圖時,user參數上的UnboundLocalError。這裏的裝飾功能:修飾器中參數的範圍不一致

def user_is(role, user=None): 
    """ 
    Takes an role (a string name of either a role or an ability) and returns the function if the user has that role 
    """ 
    def wrapper(func): 
     @wraps(func) 
     def inner(*args, **kwargs): 
      from .models import Role 
      desired_role = Role.query.filter_by(
       name=role).first() 
      if not user: 
       try: 
        from flast.ext.login import current_user as user 
       except ImportError: 
        raise ImportError(
         'User argument not passed and Flask-Login current_user could not be imported.') 
      if desired_role in user.roles: 
       return func(*args, **kwargs) 
      else: 
       # Make this do someting way better. 
       return "You do not have access" 
     return inner 
    return wrapper 

回溯表明user是未定義if not user:。我不確定這是怎麼回事。我的理解是,如果user不存在於內部函數的作用域中,那麼Python將通過嵌套函數逐層出去,直到找到它爲止。這意味着我只應得到UnboundLocalError如果user是未定義在函數中,所有函數包裝它,並全局。這顯然不是這種情況。

另一個混亂的原因是,我能夠看到使用Werkzeug調試控制檯,我的其他參數定義在此範圍內。如何定義一個參數,並將由裝飾器函數引入的另一個參數在程序流中的同一點處未定義?我想也許這是一個隻影響參數默認值的怪癖,所以我將它切換到一個必需的參數,並手動通過None,但這仍然產生了錯誤?

當其他參數在範圍內時,爲什麼user超出範圍?我怎樣才能修復這個裝飾器?

回答

3

您在內部功能導入user

from flast.ext.login import current_user as user 

這使得user在你的內在功能的本地和永遠不會被擡起頭來封閉。

不要重命名導入;相反,將user分配給current_user

def user_is(role, user=None): 
    """ 
    Takes an role (a string name of either a role or an ability) and returns the function if the user has that role 
    """ 
    def wrapper(func): 
     @wraps(func) 
     def inner(*args, **kwargs): 
      from .models import Role 
      desired_role = Role.query.filter_by(
       name=role).first() 
      if not user: 
       try: 
        from flast.ext.login import current_user 
       except ImportError: 
        raise ImportError(
         'User argument not passed and Flask-Login current_user could not be imported.') 
      else: 
       current_user = user 
      if desired_role in current_user.roles: 
       return func(*args, **kwargs) 
      else: 
       # Make this do someting way better. 
       return "You do not have access" 
     return inner 
    return wrapper 

或許命名外userdefault_user或相似。

現在user永遠不會分配給內部函數,並且仍然是外部作用域的非本地引用。

+0

這很有道理。一個後續問題可以幫助我理解:在執行導入之前引發異常時,導入如何影響'user'的範圍? – raddevon

+1

編譯器枚舉函數中的所有賦值;分配給(其中包括導入)的任何內容都會自動標記爲本地。其他一切都是一個自由變量。如果一個父範圍有一個匹配的本地,則從閉包中查找自由變量,否則它們是全局變量。你可以使用'global'關鍵字來覆蓋它(把本地標記爲全局變量),Python 3也增加了'nonlocal'關鍵字。 *其中*進口或轉讓發生無關緊要。在賦值或導入之前對名稱的任何引用都會引發'UnboundLocal'異常。 –