--- title: Python 學習筆記 tags: Note, Python --- # 前言 ###### tags: `Python` `flask` 此為用來紀錄學習Python的個人筆記,筆記內容不定時更新中... :::spoiler **Python Learning Resource** > * 書籍: https://automatetheboringstuff.com > * Python docs: https://docs.python.org/3/ > * Another really good resource: [programiz](https://www.programiz.com/python-programming/first-program), [Snakify](https://snakify.org/en/) > * [Setting up VSCode for Python]( https://www.youtube.com/watch?v=W--_EOzdTHk) ::: <br/> # Python 環境設置 在看各種專案開發教學時,常會看到建議使用**虛擬環境**來進行開發,那什麼是虛擬環境呢?虛擬環境為一種獨立的開發環境,隔離不同專案間所需要的套件版本,每個專案可以擁有自己的python版本和所需的套件,即使在同一台機器上運行也不會被影響。`virtualenv` 則是常用來建立虛擬環境的套件之一。 針對不同的專案建立不同虛擬環境有什麼優點呢? 能夠清楚了解各個專案究竟需要哪些module,後續在維護上,module在更新上也比較方便。不然光是看專案要用的module有哪些要更新、更新到什麼版本,module間的相依性,就要弄到瘋掉了😂 ## Python 版本控制 Python的版本管理工具有很多,virtualenv, pyenv, anaconda等。 我目前是使用 `pyenv` ([官方文件](https://github.com/pyenv/pyenv#basic-github-checkout)),這個開源的Python 版本管理工具。 **安裝pyenv** ```bash # Mac brew install pyenv # Windows or Linux git clone https://github.com/pyenv/pyenv.git ~/.pyenv ``` **設定pyenv環境變數** 如果使用的shell是 bash,則在 `~/.bashrc` 添加下列路徑 如果用zsh則是在 `~/.zshrc` ```bash echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.zshrc ``` 添加完路徑後,輸入下列指令使文件的配置生效 ```bash # 使當前shell 配置生效 exec $SHELL source ~/.zshrc ``` ### 常用的`pyenv`指令 **查看pyenv可安裝python 版本** ```bash pyenv install -l ``` **使用pyenv安裝特定版本python** ``` pyenv install -v 3.8.5 ``` **查看過去pyenv 安裝過的python版本** ``` pyenv versions ``` **切換python版本** ``` pyenv global 3.8.5 pyenv local 3.8.5 pyenv shell 3.8.5 ``` `global` , `local` , `shell` 差異: - `global`: 對應全局 - `local`: 對應當前資料夾 - `shell`: 對應當前shell 優先順序: `shell` > `local` > `global` ## 虛擬環境安裝 如果已經安裝好python([Windows的Python 安裝教學](https://ithelp.ithome.com.tw/articles/10210071)),就可以直接使用 `pip3` (或 `pip` ) 來安裝。 **先將pip版本升到最新** ```bash pip3 install — upgrade pip ``` **檢查目前pip有安裝什麼套件** ```bash pip3 list ``` **安裝virtualenv** ```bash # python2 pip install virtualenv # python3 pip3 install virtualenv ``` 安裝完後可以再下一次 `pip3 list` 確認有多個剛剛安裝的 `virtualenv` 套件。 **建立虛擬環境** 移動到專案資料夾內,並輸入以下指令。完成後可以在專案內看到多了個venv資料夾 ```bash # 使用環境預設python 版本 virtualenv venv # venv是自設的資料夾名 # 指定python版本 virtualenv -p ~/.pyenv/versions/3.8.5/bin/python venv ``` **進入虛擬環境** ```bash source venv/bin/activate ``` **離開虛擬環境** ``` deactivate ``` **匯出開發環境所需的所有套件** ```bash pip freeze > requirements.txt ``` **從requirement.txt下載所有所需套件** ```bash pip install -r requirements.txt ``` ##### [參考資料]: [pip workflow 管理 requirements.txt](http://pre.tir.tw/008/blog/output/pip-workflow-guan-li-requirementtxt.html) > 上述作法會有幾個缺點: > > 1. 不易升級所使用的module > 2. 不易看出此專案所依賴的top dependencies > > 解決方法:維護兩份文件 > > - `requirements-to-freeze.txt` : 紀錄專案所依賴的top-level dependencies > - `requirements.txt` : 紀錄pip freeze的結果 > > 用法: > > ```bash > cd project-repo > pip install -r requirements-to-freeze.txt --upgrade > pip freeze > requirements.txt > ``` <br/> # Python Debugger ##### [參考資料]: [官方文件](https://docs.python.org/3/library/pdb.html) <br/> ## 從terminal運行 可以在terminal使用Python Debugger執行一個腳本,舉例: ```bash $ python -m pdb my_script.py ``` 這會觸發debugger在腳本第一行指令處停止執行。 ## 從腳本內部執行 也可以在腳本內部設置斷點,如此便可以在某些特定點看變數等各種執行的訊息。以下面例子而言,用 `pdb.set_tract()` 來設斷點: ```python import pdb def test(): pdb.set_trace() return "test" print(test()) ``` 如果執行上面這個腳本會發現,在執行時直接進入debugger模式。以下可以看到一些debugger模式常用的指令。 ## Debugger常用指令 - `c`: 繼續執行 - `w`: 顯示目前正在執行的程式行的上下文訊息 - `a`: 印出當前function的參數列表 - `s`: (**s**tep)執行當前這行程式,並停在第一個能停的地方 - `n`: (**n**ext)繼續執行到當前function的下一行,或當前行直接返回(單步跳過) --- # Flask - RESTful API server ##### [參考資料]: [your first API server](https://www.fernandomc.com/posts/your-first-flask-api/) ## What is Flask 1. 以Python實作的輕量級網站框架(micro framework),只實作了核心的網頁應用程式功能(包含routing等),將其他進階的功能(像是認證、資料庫ORM)交給擴充套件(extensions)。 2. Flask內建一個實作WSGI伺服器與路由功能的Werkzeug工具集。 > **WSGI(Web Server Gateway Interface)** > 為Python定義網頁程式和伺服器溝通的介面,為Python網頁開發的標準。 > 將網頁元件分為三類:web server, web middleware, web application ## RESTful API **Resource Representational State Transfer(REST)** REST不是一種架構、協定,而是一種網路架構風格,由HTTP協定既有的幾種method (GET, POST etc.)轉換對server的各種操作,利用位置訊息來請求一份資源(URL)後,資源實體用(Json, XML等)形式表現出來。 REST = 資源 (Resource) + 表現層 (Representation) + 狀態轉化 (State Transfer) ## Introduction API(Application Programming Interface) 作為server to server 或 client to server之間的溝通管道,可以使整體的系統利用API互相請求服務而不需知道對方實作細節,僅呼叫API介面即可完成功能。 API為何需要使用表現層狀態轉移(REST)的風格來設計呢?有以下的優點 [出自WIKI](https://en.wikipedia.org/wiki/Representational_state_transfer): 1. Client-Server 2. 無狀態(Stateless) 3. 可快取 (Cachable) 4. 分層系統 (Layered System) 5. 統一接口 (Uniform Interface) ## Basic Concept **HTTP status code (狀態碼)** | 狀態碼 | 描述 | | ------ | -------------------------------------- | | 2XX | 已接受請求正常處理並返回結果 | | 3XX | 使用者代理須採取進一步動作,以完成請求 | | 4XX | 客戶端,請求有錯誤 | | 5XX | 伺服器端,內部有錯誤 | **Paging and Filtering** 若要回傳一大串集合或大量資料,可以提供分頁(Paging) 和過濾(Filtering)等機制,以增加API的效率和可用性。 - Paging `[GET]/rest/product?start=2&limit=3` - Filtering `[GET]/rest/product?introduction=iphone` **基礎架構** 用基礎的三層式架構 (Three-tier architecture)來開發RESTful API server。 ##### [參考資料]: [3-Layer 基礎架構](https://dotblogs.com.tw/clark/2014/09/09/146494)、[三層式架構的五個好處](https://www.izenda.com/5-benefits-3-tier-architecture/) <br/> ## Install Flask 在虛擬環境安裝flask ```bash pip install flask ``` ## Testing 為了測試我們寫出來的API server每個內部方法、類別都有回傳預期的結果,可以使用[Postman](https://www.postman.com/)或[Insomnia](https://insomnia.rest/)這類的工具來測試。 ### API test Postman與Insomnia功能相差不多,Insomnia介面很美,但Postman有自動化測試script的功能。 --- # Python 進階用法 ## Python Module 記錄一些用過的Python模組... ### Collections - Counter 用法: ```python= from collections import Counter str = ['a', 'a', 'b'] s = Counter(str) print(s) # Counter({'a':2, 'b':1}) ``` 此模組為一個 `dict` 的子類別,提供list中元素出現的次數,將其儲存為 `dict` 。 <!-- # Python Syntax ## 判斷是否為`None` --> ## Python Decorator 裝飾器為Python中蠻重要也很方便的一種進階用法,當開發的專案越大型,會用decorator會讓你事半功倍啊👍 ##### [參考資料]:[Python進階技巧 (3) — 神奇又美好的 Decorator ,嗷嗚!](https://medium.com/citycoddee/python%E9%80%B2%E9%9A%8E%E6%8A%80%E5%B7%A7-3-%E7%A5%9E%E5%A5%87%E5%8F%88%E7%BE%8E%E5%A5%BD%E7%9A%84-decorator-%E5%97%B7%E5%97%9A-6559edc87bc0) <br/> ### 什麼是裝飾器 裝飾器也算是一種function,由於在Python中,function的地位屬於"First-class function",可以將function當作參數傳遞並執行。 裝飾器的作用就是將相同或類似的邏輯抽出來簡化,這類的funciton就稱之為裝飾器 範例如下: ```python= def print_func_name(func): def wrap(): print("Now use function '{}'".format(func.__name__)) func() return wrap def dog_bark(): print("Bark !!!") def cat_miaow(): print("Miaow ~~~") if __name__ == "__main__": print_func_name(dog_bark)() # > Now use function 'dog_bark' # > Bark !!! print_func_name(cat_miaow)() # > Now use function 'cat_miaow' # > Miaow ~~~ ``` ### Decorator 的 Syntax Candy syntax candy(語法糖)就是讓語法簡化的語法,原本要寫數十行的code,若該語言有提供對應的語法糖,可能只需要寫個幾行或是幾個符號上去,就可以輕鬆完成。 Python 的decorator的語法糖就是`@` 因此,若將上述的例子改用語法糖的方式寫,會變成下面的樣子: ```python= def print_func_name(func): def warp(): print("Now use function '{}'".format(func.__name__)) func() return warp @print_func_name def dog_bark(): print("Bark!!") @print_func_name def cat_miaow(): print("Miaow~~") if __name__ = "__main__": dog_bark() cat_miaow() ``` ### Decorator 的有序性 decorator多層的話會採"recursive"的方式處理,若一個function有兩個以上的decorators,會先合併「最內層」的decoartor吐出新的function result,再由第二個內層的decorator吃進去,最後,再由外而內將 output印出來。 > 裝飾器包裝的順序:內 --> 外,包裝完後印出output的順序: 外 --> 內 ### Decorator 如何帶參數 讓decorator傳入參數,改成 `@print_func_name(parem=parem_variable)` 形式即可。 而原本的decorator的function要在原本的function外再包一層function用來解析decorator傳入的參數。 ```python= def print_func_name(time): def decorator(func): def warp(): print("Now use function '{}'".format(func.__name__)) print("Now Unix time is {}.".format(int(time))) func() return warp return decorator @print_func_name(time=(time.time())) def dog_bark(): print("Bark!!") ``` ### Decorator 也可以是class Decorator除了有function decorator,也有class decorator,畢竟在Python中,function 和 class 都屬於 objects。