Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

flask最近終於發佈了它的1.0版本更新,從項目開源到最近的1.0版本flask已經走過了8個年頭。

# app.pyfrom flask import Flaskapp = Flask(__name__)@app.route("/")def hello(): return "Hello World!"if __name__ == "__main__": app.run()

運行 python app.py ,打開瀏覽器訪問 http://localhost:5000/ 就可以看到頁面輸出了 Hello World!

flask的誕生於2010年的愚人節,本來它只是作者無意間寫的一個小玩具,沒想到它卻悄悄流行起來了。漫長的8年時間,flask一直沒有發佈一個嚴肅的正式版本,但是卻不能阻擋它成了github上最受好評的Python Web框架。

flask內核內置了兩個最重要的組件,所有其它的組件都是通過易擴展的插件系統集成進來的。這兩個內置的組件分別是werkzeug和jinja2。

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

werkzeug是一個用於編寫Python WSGI程序的工具包,它的結構設計和代碼質量在開源社區廣受褒揚,其源碼被尊為Python技術領域最值得閱讀的開源庫之一。

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

jinja2是一個功能極為強大的模板系統,它完美支持unicode中文,每個模板都運行在安全的沙箱環境中,使用jinja2編寫的模板代碼非常優美。

{% extends "layout.html" %}{% block body %} 
    {% for user in users %}
  • {% endfor %}
{% endblock %}

werkzeug和jinja2這兩個庫的共同特點是編寫的代碼賞心悅目,作者 Armin Ronacher 選擇這兩個庫來作為flask的基石說明作者有非常挑剔的代碼品味。那麼作者是誰呢,鐺!他是一位來自澳大利亞的帥哥!

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

好,閒話少說言歸正傳,接下來我們開始體驗flask的神奇魅力。

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

運行 python flask_pi.py ,打開瀏覽器訪問 http://localhost:5000/pi?n=1000000 ,可以看到頁面輸出 3.14159169866 ,這個值同圓周率已經非常接近。

注意 pi() 的返回值不能是浮點數,所以必須使用 str 轉換成字符串

再仔細觀察代碼,你還會注意到一個特殊的變量 request ,它看起來似乎是一個全局變量。從全局變量裡拿當前請求參數,這非常奇怪。如果在多線程環境中,該如何保證每個線程拿到的都是當前線程正在處理的請求參數呢?所以它不能是全局變量,它是線程局部變量,線程局部變量外表上和全局變量沒有差別,但是在訪問線程局部變量時,每個線程得到的都是當前線程內部共享的對象。

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

import mathimport threadingfrom flask import Flask, requestfrom flask.json import jsonifyapp = Flask(__name__)class PiCache(object): def __init__(self): self.pis = {} self.lock = threading.RLock() def set(self, n, pi): with self.lock: self.pis[n] = pi def get(self, n): with self.lock: return self.pis.get(n)cache = PiCache()@app.route("/pi")def pi(): n = int(request.args.get('n', '100')) result = cache.get(n) if result: return jsonify({"cached": True, "result": result}) s = 0.0 for i in range(1, n): s += 1.0/i/i result = math.sqrt(6*s) cache.set(n, result) return jsonify({"cached": False, "result": result})if __name__ == '__main__': app.run()

運行 python flask_pi.py ,打開瀏覽器訪問 http://localhost:5000/pi?n=1000000 ,可以看到頁面輸出

{ "cached": false, "result": 3.141591698659554}

再次刷新頁面,我們可以觀察到cached字段變成了true,說明結果確實已經緩存了

{ "cached": true, "result": 3.141591698659554}
Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

import mathimport redisfrom flask import Flask, requestfrom flask.json import jsonifyapp = Flask(__name__)class PiCache(object): def __init__(self, client): self.client = client def set(self, n, result): self.client.hset("pis", str(n), str(result)) def get(self, n): result = self.client.hget("pis", str(n)) if not result: return return float(result)client = redis.StrictRedis()cache = PiCache(client)@app.route("/pi")def pi(): n = int(request.args.get('n', '100')) result = cache.get(n) if result: return jsonify({"cached": True, "result": result}) s = 0.0 for i in range(1, n): s += 1.0/i/i result = math.sqrt(6*s) cache.set(n, result) return jsonify({"cached": False, "result": result})if __name__ == '__main__': app.run('127.0.0.1', 5000)

運行 python flask_pi.py ,打開瀏覽器訪問 http://localhost:5000/pi?n=1000000 ,可以看到頁面輸出

{ "cached": false, "result": 3.141591698659554}

再次刷新頁面,我們可以觀察到cached字段變成了true,說明結果確實已經緩存了

{ "cached": true, "result": 3.141591698659554}

重啟進程,再次刷新頁面,可以看書頁面輸出的cached字段依然是true,說明緩存結果不再因為進程重啟而丟失。

MethodView

寫過Django的朋友們可能會問,Flask是否支持類形式的API編寫方式,回答是肯定的。下面我們使用Flask原生支持的MethodView來改寫一下上面的服務。

import mathimport redisfrom flask import Flask, requestfrom flask.json import jsonifyfrom flask.views import MethodViewapp = Flask(__name__)class PiCache(object): def __init__(self, client): self.client = client def set(self, n, result): self.client.hset("pis", str(n), str(result)) def get(self, n): result = self.client.hget("pis", str(n)) if not result: return return float(result)client = redis.StrictRedis()cache = PiCache(client)class PiAPI(MethodView): def __init__(self, cache): self.cache = cache def get(self, n): result = self.cache.get(n) if result: return jsonify({"cached": True, "result": result}) s = 0.0 for i in range(1, n): s += 1.0/i/i result = math.sqrt(6*s) self.cache.set(n, result) return jsonify({"cached": False, "result": result})# as_view提供了參數可以直接注入到MethodView的構造器中# 我們不再使用request.args,而是將參數直接放進URL裡面,這就是RESTFUL風格的URLapp.add_url_rule('/pi/', view_func=PiAPI.as_view('pi', cache))if __name__ == '__main__': app.run('127.0.0.1', 5000)

我們實現了MethodView的get方法,說明該API僅支持HTTP請求的GET方法。如果要支持POST、PUT和DELETE方法,需要用戶自己再去實現這些方法。

flask默認的MethodView挺好用,但是也不夠好用,它無法在一個類裡提供多個不同URL名稱的API服務。所以接下來我們引入flask的擴展flask-classy來解決這個問題。

小試flask擴展flask-classy

使用擴展的第一步是安裝擴展 pip install flask-classy ,然後我們在同一個類裡再加一個新的API服務,計算斐波那契級數。

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程

import mathimport redisfrom flask import Flaskfrom flask.json import jsonifyfrom flask_classy import FlaskView, route # 擴展app = Flask(__name__)# pi的cache和fib的cache要分開class PiCache(object): def __init__(self, client): self.client = client def set_fib(self, n, result): self.client.hset("fibs", str(n), str(result)) def get_fib(self, n): result = self.client.hget("fibs", str(n)) if not result: return return int(result) def set_pi(self, n, result): self.client.hset("pis", str(n), str(result)) def get_pi(self, n): result = self.client.hget("pis", str(n)) if not result: return return float(result)client = redis.StrictRedis()cache = PiCache(client)class MathAPI(FlaskView): @route("/pi/") def pi(self, n): result = cache.get_pi(n) if result: return jsonify({"cached": True, "result": result}) s = 0.0 for i in range(1, n): s += 1.0/i/i result = math.sqrt(6*s) cache.set_pi(n, result) return jsonify({"cached": False, "result": result}) @route("/fib/") def fib(self, n): result, cached = self.get_fib(n) return jsonify({"cached": cached, "result": result}) def get_fib(self, n): # 遞歸,n不能過大,否則會堆棧過深溢出stackoverflow if n == 0: return 0, True if n == 1: return 1, True result = cache.get_fib(n) if result: return result, True result = self.get_fib(n-1)[0] + self.get_fib(n-2)[0] cache.set_fib(n, result) return result, FalseMathAPI.register(app, route_base='/') # 註冊到appif __name__ == '__main__': app.run('127.0.0.1', 5000) 

訪問 http://localhost:5000/fib/100 ,我們可以看到頁面輸出了

{ "cached": false, "result": 354224848179261915075}

訪問 http://localhost:5000/pi/10000000 ,計算量比較大,所以多轉了一回,最終頁面輸出了

{ "cached": false, "result": 3.141592558095893}

私信我01可以獲得整套入門資料呢!

Github上最受歡迎的Python輕量級框架Flask入門!史上最詳細教程


分享到:


相關文章: