手把手教你用Python設計乙個簡單的命令列介面

2021-09-05 13:11:22 字數 3940 閱讀 1856

對 python 程式來說,完備的命令列介面可以提公升團隊的工作效率,減少呼叫時可能碰到的困擾。今天,我們就來教大家如何設計功能完整的 python 命令列介面。

對 python 開發者來說用的最多的介面恐怕還是命令列。就拿我參與的機器學習專案來說,訓練模型和評估演算法的精確度都是通過在命令列介面執行指令碼來完成的。

所以呼叫乙個 python 指令碼的時候我們希望這段指令碼有乙個盡量簡潔方便呼叫的介面。尤其是團隊中有多名開發者的時候這一點對提公升團隊的工作效率很重要。

要讓一段指令碼方便呼叫總的來說有四個原則需要遵守:

提供預設引數值

處理呼叫出錯的情況,比如缺少引數、引數型別錯誤或者找不到檔案等

在文件中說明各個引數和選項的用法

如果執行時間較長應該提供進度條

下面我們先通過乙個簡單的例子來談談這四個原則的具體應用。例子中給出的指令碼的功能是使用凱撒碼變換對文字進行加密和解密。

caesar cipher:一種簡單的訊息編碼方式。在密碼學中,凱撒密碼,移位密碼是最簡單和最廣為人知的加密技術之一。
比如說我們想讓使用者通過命令列引數來選擇呼叫的方式是加密還是解密文字,而且使用者要從命令列傳入下面 encrypt 函式中的密匙引數 key。

首先我們得在程式中拿到命令列引數。我在網上搜「 python 命令列引數」出來的第乙個結果說讓我用 sys.argv ,那我們就來試試看它好不好用。

其實 sys.argv 只是乙個 list ,這個 list 的內容是使用者呼叫指令碼時所輸入的所有引數(其中也包括指令碼的檔名)。

如果我像下面這樣呼叫加解密的指令碼 caesar_script.py 的話:

> python caesar_script.py --key 23 --decrypt my secret message

pb vhfuhw phvvdjh

sys.argv 這個 list 的值就是:

['caesar_script.py', '--key', '23', '--decrypt', 'my', 'secret', 'message']
所以我們現在要遍歷這個 list 來找其中是否包括了「 –key 」或者「 -k 」,這樣我們就能找到密匙「 23 」。再找到「 –decrypt 」就能知道使用者是想要解密一段文字了(其實解密就是用密匙的相反數再加密一次)。

完成後的**如下:

這段**基本上遵守了我們提到的四個原則:

key 和 加密模式都設定了預設引數

指令碼可以處理像沒有文字或者缺少引數這樣比較基本的錯誤

> python caesar_script_using_sys_argv.py

usage: python caesar.py [ --key ] [ --encrypt|decrypt ]

然而不算加密函式光處理引數我們就已經寫了 39 行而且寫得一點也不優雅。我有膽說肯定還有更好的辦法來讀命令列引數。

python 標準庫裡面提供了乙個讀取命令列引數的庫——argparse 。我們來看看如果用 argparse **怎麼寫:

這樣寫也符合四項指導原則,而且對引數的說明和錯誤處理都優於使用 sys.argv 的笨辦法:

不過我個人還是覺得**裡第 7 行到第 13 行定義引數的部分寫得很囉嗦,而且我覺得引數應該使用宣告式的方法來定義。

還有乙個叫 click 的庫能實現我們想要的這些。它的基本功能和 argparse 是一樣的,但寫出來的**更優雅。

使用 click 改寫我們的加解密指令碼之後是這樣的:

我們需要的引數和選項都用裝飾器來宣告,這樣就可以在 caesar 函式裡直接使用了。

上面的**裡有幾點需要說明:

nargs 引數是說這個引數的長度是幾個詞。預設值是 1 不過用引號引起來的句子也只算乙個詞。這裡我們設為 -1 是指不限制長度。

--decrypt/--encrypt 這樣加乙個斜槓的寫法用來指明互斥的選項,它的功能和 argparse 中的 add_mutually_exclusive_group 函式類似。

click.echo 是 click 提供的乙個 print 功能,與 python 2 和 3 都相容,而且有顏色高亮功能。

我們寫的是乙個對文字加解密的指令碼,但使用者卻直接把要加密的文字打出來了,這樣有別人用這個命令列的話按幾下上方向鍵就能看到我們的使用者加密了什麼東西,這是在是有點荒唐。

我們可以選擇把使用者要加密的文字隱藏起來,或者是從檔案裡讀文字。這兩種方法都能解決我們的問題,但選擇權應該留給使用者。

同理對於加解密的結果我們也讓使用者選擇是直接在命令列輸出還是儲存成乙個檔案:

這裡我給每個引數和選項都加上了一小段說明,這樣我們的文件能更清楚一點因為我們現在引數有點多了。現在的文件是這樣的:

兩個新的引數 input_file 和 output_file 都是 click.file 型別,而且 click 幫我們處理了檔案開啟的讀寫方式和可能出現的錯誤,比如這樣:

如果使用者沒有提供 input_file 的話,如說明文件中所寫,則會讓使用者在命令列進行輸入,而且使用者輸入不再是明文了:

假設我們現在是黑客,想解密但是不知道密匙該怎麼辦呢?對凱撒加密的英文來說很容易,只要呼叫解密函式 25 次然後看看那個結果不是亂碼就行了。

要呼叫 25 次還要乙個乙個看還是太麻煩,其實只要數數哪個結果裡正確的英文詞最多就行了。下面我們就用 pyenchant 來實現自動破譯密碼:

一氣呵成!

不過我們好像還沒有提到四項原則的最後一點:

4.如果執行時間較長應該提供進度條
上面的指令碼破譯 104 個詞的文字大約需要 5 秒。考慮到要遍歷 25 個密匙還要數英文詞的個數這個時間並不算慢。

不過文字再長的話,比如 105 個詞的文字,就要花 50 秒。這就有點長了,使用者可能沒有耐心等到程式執行完就強退了。

所以我建議如果執行時間長的話最好加上進度條,關鍵是寫起來非常簡單:

不仔細看的話可能都看不出有什麼區別,因為區別只有四個字母 tqdm ,阿拉伯語中 tqdm 是進度的意思。

tqdm 庫的用法非常簡單,只要把**中的迭代器用 tqdm 括起來就行了:

for key in tqdm(range(26)):
這樣就會在命令列輸出乙個進度條,簡單得讓人不敢相信。

其實 click 的 click.progress_bar 也有類似的功能,但我覺得 click 的進度條不好看而且寫法比tqdm 稍微麻煩一點。

手把手教你用Ucos

ucos作業系統的學習 實時作業系統 任務切換,排程 分式作業系統 不可剝奪型核心 ucosii嵌入式實時作業系統的源 分為三部分 與硬體無關的核心 與處理器有關的移植 和使用者配置檔案。ucos最多支援64個任務,優先順序分別對應0 63,其中0為最高優先順序,系統保留4個最高優先順序的任務,和4...

手把手教你用Python實踐深度學習

課程共七章,採用最新版本進行教學,2018必學技術 第一章 從人工智慧到深度學習 第二章 使用tensorflow keras 建構人工神經網路 artificial neural network 第三章 卷積神經網路 convolutional neural network 第四章 迴圈神經網路 ...

手把手教你用Charles抓包

日常開發過程中難免要進行抓包,檢視服務端返回的資料是否正常,而charles可謂是抓包利器了。配置好以後,charles實際上讓電腦成了乙個中間 伺服器,我們手機上的所有請求都會經過電腦,被charles攔截,然後charles把自己偽裝成手機向我們的遠端伺服器位址傳送請求,所以charles能記錄...