內(nèi)容簡(jiǎn)介:前面兩篇文章分別介紹了JKG和Streamlit兩種方法杠纵,將python代碼發(fā)布成服務(wù)荠耽,今天我們體會(huì)一下第三種,采用Flask框架來實(shí)現(xiàn)比藻。正所謂條條大路通羅馬铝量,技術(shù)沒有什么絕對(duì)的好壞,小哥想說的是只要適合那就是最好银亲,怎么選完全看你自己慢叨,而多知道一種實(shí)現(xiàn)方法,沒壞處群凶。
1插爹、什么是Flask?
Flask是一個(gè)用Python編寫的Web應(yīng)用程序框架。什么是Web應(yīng)用程序框架赠尾?
Web Application Framework(Web應(yīng)用程序框架)或簡(jiǎn)單的Web Framework(Web框架)表示一個(gè)庫(kù)和模塊的集合力穗,使Web應(yīng)用程序開發(fā)人員能夠編寫應(yīng)用程序,而不必?fù)?dān)心協(xié)議气嫁,線程管理等低級(jí)細(xì)節(jié)当窗。
在Python生態(tài)中,F(xiàn)lask和Django是主流的兩種Web解決方案寸宵。兩者都很有名崖面,社區(qū)活躍程度差不多。
兩者可以實(shí)現(xiàn)的功能也相似梯影,如果非要對(duì)比巫员,那么Flask可以看成是毛坯房,Django是精裝修交付甲棍。但這不是說Flask不好或簡(jiǎn)陋简识,而是Flask給用戶更多靈活的配置空間,整個(gè)框架也更加輕量級(jí)感猛。
2七扰、固體潮模型計(jì)算
固體潮是啥?那我們首先科普一下陪白,在日颈走、月引潮力的作用下,固體地球產(chǎn)生的周期性形變的現(xiàn)象就叫固體潮咱士。啥地球也能變形立由,你聽的沒錯(cuò),當(dāng)太陽和月亮相對(duì)地球的位置發(fā)生改變司致,萬有引力也會(huì)發(fā)生變化拆吆,這個(gè)力能讓地球表面產(chǎn)生10cm左右量級(jí)的變化。
固體潮不像海潮那樣肉眼可見脂矫,但是確實(shí)是真實(shí)存在的,現(xiàn)代化的高精度GPS和重力儀器都可以妥妥地測(cè)量到霉晕。就拿重力固體潮來說庭再,可以好不夸張地說這是人類迄今為止能預(yù)測(cè)到的最準(zhǔn)確的地球物理現(xiàn)象,沒有之一牺堰。
在很多的現(xiàn)代化精密地球科學(xué)觀測(cè)中拄轻,固體潮的影響都需要定量扣除,這時(shí)候需要計(jì)算每個(gè)時(shí)間和地點(diǎn)上的理論固體潮伟葫,然后從儀器觀測(cè)結(jié)果中扣除這部分信號(hào)恨搓,才能得到要研究的數(shù)據(jù)對(duì)象。
今天我們以重力固體潮為例,談?wù)勗趺从?jì)算固體潮模型斧抱,并發(fā)布成一個(gè)服務(wù)常拓。固體潮模型計(jì)算方法有很多,有封閉公式型的辉浦,球諧系數(shù)方法等弄抬,這里面我們不想去深究,總之很成熟了宪郊,但是算起來還挺麻煩掂恕,代碼至少也得有個(gè)百十來行吧,公式一堆一堆的弛槐,哪如果我們用一個(gè)微服務(wù)的形式是否可以呢懊亡?
讓我們想想,輸入/輸出應(yīng)該是什么乎串?
輸入與位置相關(guān)店枣,那就是經(jīng)度/緯度/高度唄;還有時(shí)間灌闺,那就用北京時(shí)間吧艰争;
輸入解決了,那就是輸出桂对,輸出很簡(jiǎn)單就是重力固體潮理論值甩卓,有個(gè)單位用mGal吧
計(jì)算環(huán)境
計(jì)算方法有很多,我們推薦使用Geoist工具包蕉斜,怎么獲得和安裝逾柿,首先弄個(gè)開發(fā)環(huán)境,然后直接從我們的github倉(cāng)庫(kù)安裝一下宅此,命令如下:
pip install git+git://github.com/igp-gravity/geoist.git
函數(shù)用法
安裝完geoist后机错,可以直接調(diào)用tide模塊,計(jì)算與太陽相關(guān)的重力固體潮gs父腕,與月亮相關(guān)的gm和兩者之和g弱匪。
from datetime import date, datetime, timedelta
import geoist.pfm.tide as tide
gdate = datetime(int(year), int(month), int(day),
int(hour), int(min), int(sec))
gdate = gdate - timedelta(hours=8) #北京為UTC時(shí)間+8
g1 = tide.TideModel()
gm, gs, g =g1.solve_longman(slat,slon,selev,gdate)
好了,算一個(gè)點(diǎn)沒問題了璧亮,那我要算幾天的怎么搞萧诫,代碼改一下,結(jié)果見圖1:
from datetime import datetime
import geoist.pfm.tide as tide
g1= tide.TideModel()
gdate = datetime(2020, 3, 19, 10, 00, 00)
g1.duration = 5
g1.increment = 60
g1.start_time = gdate
g1.latitude = 45.0
g1.longitude = 105.0
g1.altitude = 0.0
g1.run_model()
g1.plot()
算法請(qǐng)參考:I.M. Longman "Forumlas for Computing the Tidal Accelerations Due to the Moon and the Sun" Journal of Geophysical Research, vol. 64, no. 12, 1959, pp. 2351-2355
3枝嘶、Flask封裝接口
那好了計(jì)算固體潮沒問題了帘饶,怎么能編程一個(gè)服務(wù)大家都能happy呢?好群扶,這就要Flask登場(chǎng)啦及刻,還是先安裝:
pip install Flask
然后編寫代碼镀裤,如下:
from flask import Flask,jsonify
app = Flask(__name__)
@app.route('/')
def hello():
return 'GEOIST restful API demo! Powered by Flask from Python ecosystem...'
@app.route('/user/<username>')
def profile(username):
result = {username : ['{}\'s profile'.format(username)]}
return jsonify(result)
if __name__ == '__main__':
app.run(debug = True)
將上述代碼保存成一個(gè)py文件,例如flaskdemo1.py缴饭,然后暑劝,在虛擬環(huán)境中,運(yùn)行
python flaskdemo1.py
運(yùn)行后茴扁,會(huì)提示開啟了一個(gè)本地web服務(wù)铃岔,這就是一個(gè)web的應(yīng)用啦,如圖2:
簡(jiǎn)單接口這樣就成了峭火,但是我們還想再專業(yè)一點(diǎn)毁习,別急,用flask下的專用restful插件卖丸,沒有就再安裝一下(這就是毛坯房纺且,想要啥自己裝):
pip install flask_restful
上面的代碼改造成下面樣式:
from flask import Flask,jsonify
from flask_restful import reqparse, abort, Api, Resource
from datetime import datetime
import geoist.pfm.tide as tide
app = Flask(__name__)
api = Api(app)
@app.route('/')
def hello():
return 'GEOIST restful API for Earthtide using longman method...'
class longmantide(Resource):
def post(self):
parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('lon', type=float, required=True, help='經(jīng)度d.ddd')
parser.add_argument('lat', type=float, required=True, help='緯度d.ddd')
args = parser.parse_args()
slon = float(args["lon"])
slat = float(args["lat"])
t1 = datetime.now()
g1 = tide.TideModel()
gm, gs, g = g1.solve_longman(slat,slon,0.0,t1)
return {'gm': gm, 'gs': gs, 'g':g, 't': str(t1)}
api.add_resource(longmantide, '/tide')
if __name__ == '__main__':
app.run(debug = True)
注意這次里面用了post接口,而且增加了對(duì)request參數(shù)的解析(開啟了bundle_errors設(shè)置稍浆,輸入錯(cuò)誤會(huì)提示)载碌,POST方式在運(yùn)行簡(jiǎn)單瀏覽器就不行了,這里我們用Postman演示一下提交方法衅枫,如圖3所示嫁艇。
4、生成專業(yè)API接口及OpenAPI規(guī)范文檔
上面把一個(gè)固體潮計(jì)算的簡(jiǎn)單API做好啦弦撩,但是我們要給用戶用步咪,還需要一個(gè)文檔說明,最好的方法當(dāng)然是一起發(fā)到web上益楼,要實(shí)現(xiàn)這個(gè)目標(biāo)猾漫,還要再安裝一個(gè)flask的插件——文檔生成器。
安裝方法:
pip install flasgger #http://localhost:5000/apidocs/
flasgger是將代碼里面的docstrings發(fā)布成swagger UI形式的OpenAPI兼任文檔支持模塊
上面例子中的代碼變?yōu)槿缦滦问剑?/p>
from flask import Flask,jsonify
from flask_restful import reqparse, abort, Api, Resource
from flasgger import Swagger
from datetime import datetime
import geoist.pfm.tide as tide
app = Flask(__name__)
api = Api(app)
swagger = Swagger(app)
@app.route('/')
def hello():
'''Earthtide API
---
responses:
200:
description: longmentide
'''
return 'GEOIST restful API for Earthtide using longman method...'
class longmantide(Resource):
def post(self):
'''計(jì)算重力固體潮API接口說明(基于GEOIST開發(fā)).
---
parameters:
- name: lon
type: float
required: true
- name: lat
type: float
required: true
responses:
200:
description: longmentide
schema:
id: dict
properties:
results:
type: string
description: json string
default: {'gm': gm, 'gs': gs, 'g': g, 't': time}
'''
parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('lon', type=float, required=True, help='經(jīng)度d.ddd')
parser.add_argument('lat', type=float, required=True, help='緯度d.ddd')
args = parser.parse_args()
slon = float(args["lon"])
slat = float(args["lat"])
t1 = datetime.now()
g1 = tide.TideModel()
gm, gs, g = g1.solve_longman(slat,slon,0.0,t1)
return {'gm': gm, 'gs': gs, 'g':g, 't': str(t1)}
api.add_resource(longmantide, '/tide')
if __name__ == '__main__':
app.run(debug = True)
除了代碼層次更加清晰外感凤,然后你再訪問apidocs目錄下悯周,發(fā)現(xiàn)多了一個(gè)文檔界面
一句話總結(jié):到這里一個(gè)基本的RESTful形式API就完成了,如果你有準(zhǔn)備好的服務(wù)器陪竿,可以將python代碼連同flask環(huán)境打包成一個(gè)docker禽翼,再通過CD方法部署到k8s服務(wù)集群上面,通過云基礎(chǔ)設(shè)施發(fā)布族跛,一套完整的流程走完了捐康,這樣一步步循序漸進(jìn)的來,你是否學(xué)會(huì)了呢庸蔼?