命令行開發神器 Click 入門

命令行開發神器 Click 入門

Click 是 Python Web 開發框架 Flask的作者開發的一個庫,用於快速創建命令行,目前已經整合到了最新版的 Flask 當中。Click 功能強大,使用也比較簡單,值得大家學習使用。

原文:https://funhacks.net/2016/12/20/click/

Click 是用 Python 寫的一個第三方模塊,用於快速創建命令行。我們知道,Python 內置了一個 Argparse 的標準庫用於創建命令行,但使用起來有些繁瑣,Click 相比於 Argparse,就好比 requests 相比於 urllib。

快速使用

Click 的使用大致有兩個步驟:

使用 @click.command 裝飾一個函數,使之成為命令行接口; 使用 @click.option 等裝飾函數,為其添加命令行選項等。 它的一種典型使用形式如下:

  1. <code>importclick/<code>

  2. <code>@click.com

    mand/<code>

  3. <code>@click.option('--param', default=default_value, help='description')/<code>

  4. <code>deffunc(param):/<code>

  5. <code>pass/<code>

下面,讓我們看一下官方文檔的入門例子:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.option('--count', default=1, help='Number of greetings.')/<code>

  4. <code>@click.option('--name', prompt='Your name', help='The person to greet.')/<code>

  5. <code>defhello(count, name):/<code>

  6. <code>"""Simple program that greets NAME for a total of COUNT times."""/<code>

  7. <code>forxinrange(count):/<code>

  8. <code>click.echo('Hello %s!' % name)/<code>

  9. <code>if__name__ == '__main__':/<code>

  10. <code>hello/<code>

在上面的例子中,函數 hello 有兩個參數:count 和 name,它們的值從命令行中獲取。

  • @click.command 使函數 hello 成為命令行接口;

  • @click.option 的第一個參數指定了命令行選項的名稱,可以看到,count 的默認值是 1;

  • 使用 click.echo 進行輸出是為了獲得更好的兼容性,因為 print 在 Python2 和 Python3 的用法有些差別。

看看執行情況:

  1. <code>$ python hello.py/<code>

  2. <code>Your name: Ethan # 這裡會顯示 'Your name: '(對應代碼中的 prompt),接受用戶輸入/<code>

  3. <code>Hello Ethan!/<code>

  4. <code>$ python hello.py --help # click 幫我們自動生成了 `--help` 用法/<code>

  5. <code>Usage: hello.py [OPTIONS]/<code>

  6. <code>Simple program that greets NAME fora total of COUNT times./<code>

  7. <code>Options:/<code>

  8. <code>--count INTEGER Number of greetings./<code>

  9. <code>--name TEXT The person to greet./<code>

  10. <code>--help Show thismessageandexit./<code>

  11. <code>$ python hello.py --count 3--name Ethan # 指定 count 和 name 的值/<code>

  12. <code>Hello Ethan!/<code>

  13. <code>Hello Ethan!/<code>

  14. <code>Hello Ethan!/<code>

  15. <code>$ python hello.py --count=3--name=Ethan # 也可以使用 `=`,和上面等價/<code>

  16. <code>Hello Ethan!/<code>

  17. <code>Hello Ethan!/<code>

  18. <code>Hello Ethan!/<code>

  19. <code>$ python hello.py --name=Ethan # 沒有指定 count,默認值是 1/<code>

  20. <code>Hello Ethan!/<code>

click.option

option 最基本的用法就是通過指定命令行選項的名稱,從命令行讀取參數值,再將其傳遞給函數。在上面的例子,我們看到,除了設置命令行選項的名稱,我們還會指定默認值,help 說明等,option 常用的設置參數如下:

  • default: 設置命令行參數的默認值

  • help: 參數說明

  • type: 參數類型,可以是 string, int, float 等

  • prompt: 當在命令行中沒有輸入相應的參數時,會根據 prompt 提示用戶輸入

  • nargs: 指定命令行參數接收的值的個數

下面,我們再看看相關的例子。

指定 type

我們可以使用 type 來指定參數類型:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.option('--rate', type=float, help='rate') # 指定 rate 是 float 類型/<code>

  4. <code>

    defshow(rate):/<code>

  5. <code>click.echo('rate: %s' % rate)/<code>

  6. <code>if__name__ == '__main__':/<code>

  7. <code>show/<code>

執行情況:

  1. <code>$ python click_type.py --rate 1/<code>

  2. <code>rate: 1.0/<code>

  3. <code>$ python click_type.py --rate 0.66/<code>

  4. <code>rate: 0.66/<code>

可選值

在某些情況下,一個參數的值只能是某些可選的值,如果用戶輸入了其他值,我們應該提示用戶輸入正確的值。在這種情況下,我們可以通過 click.Choice 來限定:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.option('--gender', type=click.Choice(['man', 'woman'])) # 限定值/<code>

  4. <code>defchoose(gender):/<code>

  5. <code>click.echo('gender: %s' % gender)/<code>

  6. <code>if__name__ == '__main__':/<code>

  7. <code>choose/<code>

執行情況:

  1. <code>$ python click_choice.py --gender boy/<code>

  2. <code>Usage: click_choice.py [OPTIONS]/<code>

  3. <code>Error: Invalid value for"--gender": invalid choice: boy. (choosefromman, woman)/<code>

  4. <code>$ python click_choice.py --gender man/<code>

  5. <code>gender: man/<code>

多值參數

有時,一個參數需要接收多個值。option 支持設置固定長度的參數值,通過 nargs 指定。

看看例子就明白了:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.option('--center', nargs=2, type=float, help='center of the circle')/<code>

  4. <code>@click.option('--radius', type=float, help='radius of the circle')/<code>

  5. <code>defcircle(center, radius):/<code>

  6. <code>click.echo('center: %s, radius: %s' % (center, radius))/<code>

  7. <code>if__name__ == '__main__':/<code>

  8. <code>circle/<code>

在上面的例子中,option 指定了兩個參數:center 和 radius,其中,center 表示二維平面上一個圓的圓心座標,接收兩個值,以元組的形式將值傳遞給函數,而 radius 表示圓的半徑。

執行情況:

  1. <code>$ python click_multi_values.py --center 34--radius10/<code>

  2. <code>center: (3.0,4.0), radius:10.0/<code>

  3. <code>$ python click_multi_values.py --center 345--radius10/<code>

  4. <code>Usage: click_multi_values.py [OPTIONS]/<code>

  5. <code>Error: Got unexpected extra argument (5)/<code>

輸入密碼

有時,在輸入密碼的時候,我們希望能隱藏顯示。option 提供了兩個參數來設置密碼的輸入:hideinput 和 confirmationpromt,其中,hideinput 用於隱藏輸入,confirmationpromt 用於重複輸入。

看看例子:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.option('--password', prompt=True

    , hide_input=True, confirmation_prompt=True)/<code>

  4. <code>definput_password(password):/<code>

  5. <code>click.echo('password: %s' % password)/<code>

  6. <code>if__name__ == '__main__':/<code>

  7. <code>input_password/<code>

執行情況:

  1. <code>$ python click_password.py/<code>

  2. <code>Password: # 不會顯示密碼/<code>

  3. <code>Repeat forconfirmation: # 重複一遍/<code>

  4. <code>password:

    666666/<code>

由於上面的寫法有點繁瑣,click 也提供了一種快捷的方式,通過使用 @click.password_option,上面的代碼可以簡寫成:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.password_option/<code>

  4. <code>definput_password(password):/<code>

  5. <code>click.echo('password: %s' % password)/<code>

  6. <code>if__name__ == '__main__':/<code>

  7. <code>input_password/<code>

改變命令行程序的執行

有些參數會改變命令行程序的執行,比如在終端輸入 python 是進入 python 控制檯,而輸入 python --version 是打印 python 版本。Click 提供 eager 標識對參數名進行標識,如果輸入該參數,則會攔截既定的命令行執行流程,跳轉去執行一個回調函數。

讓我們看看例子:

  1. <code>importclick/<code>

  2. <code>defprint_version(ctx, param, value):/<code>

  3. <code>ifnotvalueorctx.resilient_parsing:/<code>

  4. <code>return/<code>

  5. <code>click.echo('Version 1.0')/<code>

  6. <code>ctx.exit/<code>

  7. <code>@click.command/<code>

  8. <code>@click.option('--version', is_flag=True, callback=print_version,/<code>

  9. <code>expose_value=False, is_eager=True)/<code>

  10. <code>@click.option('--name', default='Ethan', help='name')/<code>

  11. <code>defhello(name):/<code>

  12. <code>click.echo('Hello %s!' % name)/<code>

  13. <code>if__name__ == '__main__':/<code>

  14. <code>hello/<code>

其中:

  • is_eager=True 表明該命令行選項優先級高於其他選項;

  • expose_value=False 表示如果沒有輸入該命令行選項,會執行既定的命令行流程;

  • callback 指定了輸入該命令行選項時,要跳轉執行的函數;

執行情況:

  1. <code>$ python click_eager.py/<code>

  2. <code>Hello Ethan!/<code>

  3. <code>$ python click_eager.py --version # 攔截既定的命令行執行流程/<code>

  4. <code>Version 1.0/<code>

  5. <code>$ python click_eager.py --name Michael/<code>

  6. <code>Hello Michael!/<code>

  7. <code>$ python click_eager.py --version --name Ethan # 忽略 name 選項/<code>

  8. <code>Version 1.0/<code>

click.argument

我們除了使用 @click.option 來添加可選參數,還會經常使用 @click.argument 來添加固定參數。它的使用和 option 類似,但支持的功能比 option 少。

入門使用

下面是一個簡單的例子:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.argument('coordinates')/<code>

  4. <code>defshow(coordinates):/<code>

  5. <code>click.echo('coordinates: %s' % coordinates)/<code>

  6. <code>if__name__ == '__main__':/<code>

  7. <code>show/<code>

看看執行情況:

  1. <code>$ python click_argument.py # 錯誤,缺少參數 coordinates/<code>

  2. <code>Usage: click_argument.py [OPTIONS] COORDINATES/<code>

  3. <code>Error: Missing argument "coordinates"./<code>

  4. <code>$ python click_argument.py --help # argument 指定的參數在 help 中沒有顯示/<code>

  5. <code>Usage: click_argument.py [OPTIONS] COORDINATES/<code>

  6. <code>Options:/<code>

  7. <code>--help Show thismessageandexit./<code>

  8. <code>$ python click_argument.py --coordinates 10# 錯誤用法,這是 option 參數的用法/<code>

  9. <code>Error: nosuch option: --coordinates/<code>

  10. <code>$ python click_argument.py

    10# 正確,直接輸入值即可/<code>

  11. <code>coordinates: 10/<code>

多個 argument

我們再來看看多個 argument 的例子:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.argument('x')/<code>

  4. <code>@click.argument('y')/<code>

  5. <code>@click.argument('z')/<code>

  6. <code>defshow(x, y, z):/<code>

  7. <code>click.echo('x: %s, y: %s, z:%s' % (x, y, z))/<code>

  8. <code>if__name__ == '__main__':/<code>

  9. <code>show/<code>

執行情況:

  1. <code>$ python click_argument.py 102030/<code>

  2. <code>x: 10, y:20, z:

    30/<code>

  3. <code>$ python click_argument.py 10/<code>

  4. <code>Usage: click_argument.py [OPTIONS] X Y Z/<code>

  5. <code>Error: Missing argument "y"./<code>

  6. <code>$ python click_argument.py 1020/<code>

  7. <code>Usage: click_argument.py [OPTIONS] X Y Z/<code>

  8. <code>Error: Missing argument "z"./<code>

  9. <code>$ python click_argument.py 10203040/<code>

  10. <code>Usage: click_argument.py [OPTIONS] X Y Z/<code>

  11. <code>Error: Got unexpected extra argument (40)/<code>

不定參數

argument 還有另外一種常見的用法,就是接收不定量的參數,讓我們看看例子:

  1. <code>importclick/<code>

  2. <code>@click.command/<code>

  3. <code>@click.argument('src', nargs=-1)/<code>

  4. <code>@click.argument('dst', nargs=1

    )/<code>

  5. <code>defmove(src, dst):/<code>

  6. <code>click.echo('move %s to %s' % (src, dst))/<code>

  7. <code>if__name__ == '__main__':/<code>

  8. <code>move/<code>

其中,nargs=-1 表明參數 src 接收不定量的參數值,參數值會以 tuple 的形式傳入函數。如果 nargs 大於等於 1,表示接收 nargs 個參數值,上面的例子中,dst 接收一個參數值。

讓我們看看執行情況:

  1. <code>$ python click_argument.py file1 trash # class="lazy" src="//p2.ttnews.xyz/loading.gif" data-original=('file1',) dst='trash'/<code>

  2. <code>move (u'file1',) to trash/<code>

  3. <code>$ python click_argument.py file1 file2 file3 trash # class="lazy" data-original=('file1', 'file2', 'file3') dst='trash'/<code>

  4. <code>move (u'file1', u'file2', u'file3') to trash/<code>

彩色輸出

在前面的例子中,我們使用 click.echo 進行輸出,如果配合 colorama 這個模塊,我們可以使用 click.secho 進行彩色輸出,在使用之前,使用 pip 安裝 colorama:

  1. <code>$ pip install colorama/<code>

看看例子:

  1. <code>importclick/<code>

  2. <code>@click

    .command/<code>

  3. <code>@click.option('--name', help='The person to greet.')/<code>

  4. <code>defhello(name):/<code>

  5. <code>click.secho('Hello %s!' % name, fg='red', underline=True)/<code>

  6. <code>click.secho('Hello %s!' % name, fg='yellow', bg='black')/<code>

  7. <code>if__name__ == '__main__':/<code>

  8. <code>hello/<code>

其中:

  • fg 表示前景顏色(即字體顏色),可選值有:BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE 等;

  • bg 表示背景顏色,可選值有:BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE 等;

  • underline 表示下劃線,可選的樣式還有:dim=True,bold=True 等;

小結

使用 click.command 裝飾一個函數,使其成為命令行接口。 使用 click.option 添加可選參數,支持設置固定長度的參數值。 使用 click.argument 添加固定參數,支持設置不定長度的參數值。


分享到:


相關文章: