搜尋

首頁  >  問答  >  主體

python - flask 使用者權限修飾器

看書發現這段程式碼有點雲裡霧裡,裝飾器有點昏,希望幫我解析下這段程式碼! !

from functools import wraps
from flask import abort
from flask_login import current_user
from .models import Permission


def permission_required(permission):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.can(permission):
                abort(403)
            return f(*args, **kwargs)
        return decorated_function
    return decorator


def admin_required(f):
    return permission_required(Permission.ADMINISTER)(f)
PHP中文网PHP中文网2780 天前688

全部回覆(2)我來回復

  • 迷茫

    迷茫2017-05-18 10:52:23

    首先你要先理解裝飾器的原理:

    @abcd
    def f():
        pass

    其實與下面的語句等價:

    def f():
        pass
    f=abcd(f)

    我們現在有一個函數abcd,這個函數的本質是:接受另一個函數當做參數,並且回傳一個函數。 (至於回傳的函數用來幹嘛那就是你的事了)。這時候,abcd只是個函數而已,還不是修飾語。
    而由於以下這個需求十分的常見:有一個舊函數,我們又想定義一個新函數,這個新函數大體上功能與舊函數接近,只是多了一點點的新功能,比如打印個日期,判斷個權限什麼的。那麼定義新函數的過程中一定會呼叫這個舊函數,然而新函數其實改變不大,舊函數往往也沒用了(因為一般我們後面都是用的新函數了),那麼為了不讓命名空間變得混亂和方便開發,我們可以簡單的就用舊函數的名字來表示新函數,也就是在定義完了一個新函數之後,我們把它的名字又變回以前的f,而以前的f就不要了。所以我們可以這樣做:定義一個函數abcd,它接受一個函數f,並且傳回一個新的函數,再把它的回傳值(新函數),再賦值給f(python裡函數名稱也可以賦值,成為另一個函數)。這實際上就是我上面的第二段程式碼所做的事情。由於這個需求太常見,所以python專門為它定義了語法。你不是每次都要f=abcd(f)嗎,那你就直接在f的def語句前面加個@abcd得了,也別每次再寫後面那句了,不僅麻煩,有時還容易誤解。這時候,abcd就成為了裝飾器。
    了解了這個等價關係,你的函數就好理解了:當你在某處使用的時候,是這樣的

    @permission_required(permission)
    def old():
        pass

    等價於

    def old():
        pass
    old = permission_required(permission)(old)

    優先權相同,運算從左到右,先計算permission_required(permission),它返回decorator是一个函数,这时候变成old = decorator(old)为了满足成为修饰器的要求,这个decorator应当返回一个新函数才行,在这里就是decorated_function,所以原赋值语句变成old = decorated_function。到这里比较清晰了,把一个函数的名字赋值给一个变量(old),所以old就变成了decorated_function這裡所定義的函數。
    過程也就是:

    old = permission_required(permission)(old)
    -> old = decorator(old)
    -> old = decorated_function

    回覆
    0
  • 给我你的怀抱

    给我你的怀抱2017-05-18 10:52:23

    希望下面程式碼對你有幫助

    from functools import wraps
    
    def permission_required(permission):
        """返回装饰器,装饰器中使用入参 permission
        """
        def decorator(f):
            @wraps(f)
            def decorated_function(*args, **kwargs):
                if not permission:
                    print '403'
                    return
                return f(*args, **kwargs)
            return decorated_function
        return decorator
    
    
    def admin_required_true(f):
        """装饰器函数,返回装饰器
        """
        return permission_required(True)(f)
    
    def admin_required_false(f):
        """装饰器函数,返回装饰器
        """
        return permission_required(False)(f)
    
    @admin_required_true
    def foo():
        """使用装饰器
        """
        print 'foo'
        
    @admin_required_false
    def bar():
        """使用装饰器
        """
        print 'bar'
    
    foo()
    bar()

    運行結果:

    foo
    403

    回覆
    0
  • 取消回覆