1. 程式人生 > >讓你如紳士般基於描述編寫 Python 命令列工具的開源專案:docopt

讓你如紳士般基於描述編寫 Python 命令列工具的開源專案:docopt


作者:HelloGitHub-Prodesire

HelloGitHub 的《講解開源專案》系列,專案地址:https://github.com/HelloGitHub-Team/Article

一、前言

在本系列前面四篇文章中,我們介紹了 argparse 的方方面面。它無疑是強大的,但使用方式上略顯麻煩。需要先設定解析器,再定義引數,再解析命令列,最後實現業務邏輯。

而今天要介紹的 docopt 則是站在一個全新的視角來審視命令列。你可曾想過,一個命令列程式的幫助資訊其實已然包含了這個命令列的完整元資訊,那麼是否可以通過定義幫助資訊來定義命令列呢?docopt 就是基於這樣的想法去設計的。

本系列文章預設使用 Python 3 作為直譯器進行講解。
若你仍在使用 Python 2,請注意兩者之間語法和庫的使用差異哦~

二、介紹

docopt 基於長久以來在幫助資訊和手冊中描述程式介面的約定,其介面描述是形式化的幫助資訊。它能夠根據命令列程式中定義的介面描述,來自動生成解析器。

三、快速開始

3.1 定義介面描述/幫助資訊

第一步要做的就是命令列程式的定義介面描述或者是幫助資訊,這樣 docopt 就能知道命令列的元資訊,從而自動解析。

介面描述通常定義在一個模組的文件字串中,我們仍然以在 Python 命令列之旅:初探 argparse 的例子為例,講解如何使用 docopt 來定義介面描述。

cmd.py 中,我們定義如下介面描述:

"""Num accumulator.

Usage:
  cmd.py [--sum] <num>...
  cmd.py (-h | --help)

Options:
  -h --help     Show help.
  --sum         Sum the nums (default: find the max).
"""

在上面的介面描述中,我們定義了命令列程式 cmd.py 接受一個或多個數字 num,而 --sum 選項則是可選,-h--help 則輸出幫助資訊。

若提供 --sum,則累加給定的數字;反之,取給定多個數字中最大的一個。這個業務邏輯我們將在後文實現。

3.2 解析命令列

定義好介面描述後,就可以使用 docopt 進行解析,寫法非常簡單:

from docopt import docopt

arguments = docopt(__doc__, options_first=True)
print(arguments)

由於我們之前是將介面描述定義在模組的文件字串中,那麼直接使用 __doc__ 即可獲得介面描述。然後使用 docopt 函式即可解析命令列為引數字典。為了支援負數,我們將 options_first 設定為 True

當我們執行 python3 cmd.py --sum 1 2 3 時,將會得到如下內容:

{'--help': False,
 '--sum': True,
 '<num>': ['1', '2', '3']}

可以看到:

  • 沒有提供 -h 或者 --help,所以 arguments--helpFalse
  • 提供了 --sum,所以 arguments--sumTrue
  • 提供了 <num>...1 2 3,所以 arguments<num>['1', '2', '3']

3.3 業務邏輯

獲得瞭解析後的命令列引數,我們就可以根據自己的業務需求做進一步處理了。
在本文示例中,我們希望當用戶提供 --sum 選項時,是對給定的一組數字求和;反之則是取最大值,那麼就可以這麼寫:

nums = (int(num) for num in arguments['<num>'])

if arguments['--sum']:
    result = sum(nums)
else:
    result = max(nums)

print(result) # 基於上文的 python3 cmd.py --sum 1 2 3 引數,其結果為 6

3.4 程式碼梳理

使用 docopt 的方式非常簡單,我們將上文的程式碼彙總下,以有一個更清晰的認識:

# cmd.py
# 1. 定義介面描述
"""Num accumulator.

Usage:
  cmd.py [--sum] <num>...
  cmd.py (-h | --help)

Options:
  -h --help     Show help.
  --sum         Sum the nums (default: find the max).
"""

from docopt import docopt

# 2. 解析命令列
arguments = docopt(__doc__, options_first=True)

# 3. 業務邏輯
nums = (int(num) for num in arguments['<num>'])

if arguments['--sum']:
    result = sum(nums)
else:
    result = max(nums)

print(result)

若我們需要對一組數字求和,只需執行:

$ python3 cmd.py --sum 1 0 -1
0

若我們需要對一組數字求最大值,只需執行:

$ python3 cmd.py 1 0 -1
1

我們還可以通過 -h--help 引數檢視使用說明和幫助,也就是我們定義的介面描述。

四、小節

docopt 的思路非常簡單,就是定義介面描述,然後幫你解析命令列為引數字典,接下來就根據這個字典來編寫業務邏輯。

重點就是在於如何定義介面描述,在下一篇文章中,我們來深入瞭解下如何定義命令、選項、位置引數等介面描述。


『講解開源專案系列』——讓對開源專案感興趣的人不再畏懼、讓開源專案的發起者不再孤單。跟著我們的文章,你會發現程式設計的樂趣、使用和發現參與開源專案如此簡單。歡迎留言聯絡我們、加入我們,讓更多人愛上開源、貢獻開源