W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
Python 擁有一件非常有趣的特性,那就是函數(shù)裝飾器。這個特性允許您使用一些 非常簡介的語法編輯 Web 應(yīng)用。因?yàn)?Flask 中的每個視圖都是一個函數(shù)裝飾器, 這些裝飾器被用來將附加的功能注入到一個或者多個函數(shù)中。 route() 裝飾器您可能已經(jīng)使用過了。但是在一些情況下您需要實(shí)現(xiàn)自己的裝飾器。例如, 您有一個僅供登陸后的用戶訪問的視圖,如果未登錄的用戶試圖訪問,則把用戶 轉(zhuǎn)接到登陸界面。這個例子很好地說明了裝飾器的用武之地。
現(xiàn)在讓我們實(shí)現(xiàn)一個這樣的裝飾器。裝飾器是指返回函數(shù)的函數(shù),它其實(shí)非常簡單。 您僅需要記住,當(dāng)實(shí)現(xiàn)一個類似的東西,其實(shí)是更新 __name__ 、 __module__ 以及函數(shù)的其他一些屬性,這件事情經(jīng)常被遺忘。但是您不必親自動手,這里 有一個專門用于處理這些的以裝飾器形式調(diào)用的函數(shù)(functools.wraps() )。
這個例子家丁登陸頁面的名字是 'login' 并且當(dāng)前用戶被保存在 g.user 當(dāng)中, 如果么有用戶登陸, g.user 會是 None:
from functools import wraps
from flask import g, request, redirect, url_for
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for('login', next=request.url))
return f(*args, **kwargs)
return decorated_function
所以您怎么使用這些裝飾器呢?將它加為視圖函數(shù)外最里層的裝飾器。當(dāng)添加更多 裝飾器的話,一定要記住 route() 考試最外面的:
@app.route('/secret_page')
@login_required
def secret_page():
pass
試想你有一個運(yùn)算量很大的函數(shù),而且您希望能夠?qū)⑸傻慕Y(jié)果在一段時間內(nèi) 緩存起來,一個裝飾器將會非常適合用于干這種事。我們假定您已經(jīng)參考 緩存 中提到的內(nèi)容配置好了緩存功能。
這里有一個用作例子的緩存函數(shù),它從一個指定的前綴(通常是一個格式化字符串) 和當(dāng)前請求的路徑生成一個緩存鍵。請注意我們創(chuàng)建了一個這樣的函數(shù): 它先創(chuàng)建 一個裝飾器,然后用這個裝飾器包裝目標(biāo)函數(shù)。聽起來很復(fù)雜?不幸的是,這的確 有些難,但是代碼看起來會非常直接明了。
被裝飾器包裝的函數(shù)將能做到如下幾點(diǎn):
代碼如下:
from functools import wraps
from flask import request
def cached(timeout=5 * 60, key='view/%s'):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key % request.path
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator
注意,這段代碼假定一個示例用的 cache 對象時可用的。請參考 緩存 以獲取更多信息。
TurboGears 的家伙們前一段時間發(fā)明了一種新的常用范式,那就是模板裝飾器。 這個裝飾器的關(guān)鍵在于,您將想要傳遞給模板的值組織成字典的形式,然后從 視圖函數(shù)中返回,這個模板將會被自動渲染。這樣,下面的三個例子就是等價的了:
@app.route('/')
def index():
return render_template('index.html', value=42)
@app.route('/')
@templated('index.html')
def index():
return dict(value=42)
@app.route('/')
@templated()
def index():
return dict(value=42)
正如您所看到的,如果沒有模板名被指定,那么他會使用 URL 映射的最后一部分, 然后將點(diǎn)轉(zhuǎn)換為反斜杠,最后添加上 '.html' 作為模板的名字。當(dāng)裝飾器 包裝的函數(shù)返回,返回的字典就會被傳遞給模板渲染函數(shù)。如果 None 被返回 了,那么相當(dāng)于一個空的字典。如果非字典類型的對象被返回,函數(shù)將照原樣 將那個對象再次返回。這樣您就可以繼續(xù)使用重定向函數(shù)或者返回簡單的字符串了。
這是那個裝飾器的源代碼:
from functools import wraps
from flask import request
def templated(template=None):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
template_name = template
if template_name is None:
template_name = request.endpoint \
.replace('.', '/') + '.html'
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}
elif not isinstance(ctx, dict):
return ctx
return render_template(template_name, **ctx)
return decorated_function
return decorator
如果您希望使用 werkzeug 路由系統(tǒng)來獲得更多的靈活性。您需要將終點(diǎn)(Endpoint) 像 Rule 中定義的那樣映射起來。通過一個裝飾器 是可以做到的,例如:
from flask import Flask
from werkzeug.routing import Rule
app = Flask(__name__)
app.url_map.add(Rule('/', endpoint='index'))
@app.endpoint('index')
def my_index():
return "Hello world"
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: