Python 命令列之旅:深入 click 之引數篇
作者:HelloGitHub-Prodesire
HelloGitHub 的《講解開源專案》系列,專案地址:https://github.com/HelloGitHub-Team/Article
一、前言
在上一篇文章中,我們初步掌握了 click
的簡單用法,並瞭解到它與 argparse
和 docopt
的不同。接下來,將深入介紹 click
的各類用法,以讓你能輕鬆打造複雜的命令列程式。
在概念上, click
把命令列分為 3 個組成:引數、選項和命令。
引數
就是跟在命令後的除選項外的內容,比如git add a.txt
中的a.txt
就是表示檔案路徑的引數選項
就是以-
--
開頭的引數,比如-f
、--file
命令
就是命令列的初衷了,比如git
就是命令,而git add
中的add
則是git
的子命令
本系列文章預設使用 Python 3 作為直譯器進行講解。
若你仍在使用 Python 2,請注意兩者之間語法和庫的使用差異哦~
二、引數
2.1 基本引數
基本引數
就是通過位置裡指定引數值。
比如,我們可以指定兩個位置引數 x
和 y
,先新增的 x
位於第一個位置,後加入的 y
位於第二個位置。那麼在命令列中輸入 1 2
的時候,分別對應到的就是 x
和 y
:
@click.command() @click.argument('x') @click.argument('y') def hello(x, y): print(x, y)
2.2 引數型別
引數型別
就是將引數值作為什麼型別去解析,預設情況下是字串型別。我們可以通過 type
入參來指定引數型別。
click
支援的引數型別多種多樣:
str
/click.STRING
表示字串型別,這也是預設型別int
/click.INT
表示整型float
/click.FLOAT
表示浮點型bool
/click.BOOL
表示布林型。很棒之處在於,它會識別表示真/假的字元。對於1
、yes
、y
和true
會轉化為True
;0
、no
、n
和false
會轉化為False
click.UUID
表示 UUID,會自動將引數轉換為uuid.UUID
物件click.FILE
click.PATH
表示路徑click.Choice
表示選擇選項click.IntRange
表示範圍選項
同 argparse
一樣,click
也支援自定義型別,需要編寫 click.ParamType
的子類,並重載 convert
方法。
官網提供了一個例子,實現了一個整數型別,除了普通整數之外,還接受十六進位制和八進位制數字, 並將它們轉換為常規整數:
class BasedIntParamType(click.ParamType):
name = "integer"
def convert(self, value, param, ctx):
try:
if value[:2].lower() == "0x":
return int(value[2:], 16)
elif value[:1] == "0":
return int(value, 8)
return int(value, 10)
except TypeError:
self.fail(
"expected string for int() conversion, got "
f"{value!r} of type {type(value).__name__}",
param,
ctx,
)
except ValueError:
self.fail(f"{value!r} is not a valid integer", param, ctx)
BASED_INT = BasedIntParamType()
2.3 檔案引數
在基本引數的基礎上,通過指定引數型別,我們就能構建出各類引數。
檔案引數
是非常常用的一類引數,通過 type=click.File
指定,它能正確處理所有 Python 版本的 unicode 和 位元組,使得處理檔案十分方便。
@click.command()
@click.argument('input', type=click.File('rb')) # 指定檔案為二進位制讀
@click.argument('output', type=click.File('wb')) # 指定檔案為二進位制寫
def inout(input, output):
while True:
chunk = input.read(1024) # 此時 input 為檔案物件,每次讀入 1024 位元組
if not chunk:
break
output.write(chunk) # 此時 output 為檔案物件,寫入上步讀入的內容
2.4 檔案路徑引數
檔案路徑引數
用來處理檔案路徑,可以對路徑做是否存在等檢查,通過 type=click.Path
指定。不論檔名是 unicode 還是位元組型別,獲取到的引數型別都是 unicode 型別。
@click.command()
@click.argument('filename', type=click.Path(exists=True)) # 要求給定路徑存在,否則報錯
def hello(filename):
click.echo(click.format_filename(filename))
如果檔名是以 -
開頭,會被誤認為是命令列選項,這個時候需要在引數前加上 --
和空格,比如
$ python hello.py -- -foo.txt
-foo.txt
2.5 選擇項引數
選擇項引數
用來限定引數內容,通過 type=click.Choice
指定。
比如,指定檔案讀取方式限制為 read-only
和 read-write
:
@click.command()
@click.argument('mode', type=click.Choice(['read-only', 'read-write']))
def hello(mode):
click.echo(mode)
2.6 可變引數
可變引數
用來定義一個引數可以有多個值,且能通過 nargs
來定義值的個數,取得的引數的變數型別為元組。
若 nargs=N
,N
為一個數字,則要求該引數提供 N 個值。若 N
為 -1
則接受提供無數量限制的引數,如:
@click.command()
@click.argument('foo', nargs=-1)
@click.argument('bar', nargs=1)
def hello(foo, bar):
pass
如果要實現 argparse
中要求引數數量為 1 個或多個的功能,則指定 nargs=-1
且 required=True
即可:
@click.command()
@click.argument('foo', nargs=-1, required=True)
def hello(foo, bar):
pass
2.7 從環境變數讀取引數
通過在 click.argument
中指定 envvar
,則可讀取指定名稱的環境變數作為引數值,比如:
@click.command()
@click.argument('filename', envvar='FILENAME')
def hello(filename):
print(filename)
執行如下命令檢視效果:
$ FILENAME=hello.txt python3 hello.py
hello.txt
而在 argparse
中,則需要自己從環境變數中讀取。
三、小節
本文講解了 click
中基本引數的用法,在此基礎上介紹了各種型別的引數,最後說明了從環境變數中獲取引數值的寫法。
在下一篇文章中,我們來繼續深入瞭解 click
的功能,看看它都支援什麼樣的“選項”。
『講解開源專案系列』——讓對開源專案感興趣的人不再畏懼、讓開源專案的發起者不再孤單。跟著我們的文章,你會發現程式設計的樂趣、使用和發現參與開源專案如此簡單。歡迎留言聯絡我們、加入我們,讓更多人愛上開源、貢獻開源