在之前的一篇文章输出彩色命令行里,我介绍了 Colorama 的基本使用方法。但作为一个命令行程序,除了好看的五颜六色的输出,还需要解析命令行参数。
一个简单好用的库——click,不仅集成了 Colorama,还提供了更简单的命令行解析。
Command(命令)
使用click创建一个命令十分简单:
import click
@click.command(help="just say hi")
def sayhi():
print('hi')
if __name__ == "__main__":
sayhi()
尝试执行这个文件,你将能看一个平凡的hi
。
那么接下来,尝试让它接受一些参数、或者选项。
Argument(参数)
import click
@click.command(help="just say hi")
@click.argument("name")
def sayhi(name):
print(f'hi {name}')
if __name__ == "__main__":
sayhi()
再尝试直接运行这个文件,你能看到如下报错
⚡ AberS@SHEERAN ~\Desktop
❯ python .\sayhi.py
Usage: sayhi.py [OPTIONS] NAME
Try "sayhi.py --help" for help.
Error: Missing argument "NAME".
或许你在想,是不是因为调用sayhi
的时候缺少了参数name
,但并不是。@click.command
会将函数签名抹去,当你直接调用sayhi
的时候,实际直接调用的并不是sayhi
。
试试执行python sayhi.py aber
这个命令,你将能看到hi aber
。
多值参数
接下来尝试让这个小脚本同时向更多人打招呼:
import click
@click.command(help="just say hi")
@click.argument("name", nargs=-1)
def sayhi(name):
print('hi', ", ".join(name))
if __name__ == "__main__":
sayhi()
nargs
选项允许 argument 接受更多的内容,当它的值为正整数时,接受指定数目的内容;当它的值为-1
时,它将接受所有的参数。所以一个command下,只能有一个argument的nargs
被指定为-1
。
❯ python .\sayhi.py aber alice bob sherry
hi aber, alice, bob, sherry
Option(选项)
选项分长选项(--option
)和短选项(-o
),一般来说是相对应的。
import click
@click.command(help="just say hi")
@click.option("-k", "--keyword", required=True)
@click.argument("name", nargs=-1)
def sayhi(name, keyword):
print('hi', keyword, ", ".join(name))
if __name__ == "__main__":
sayhi()
必须选项
执行命令时不带选项,则默认为None
。但如果给option加上required=True
,则必须携带此选项。
❯ python .\sayhi.py aber
Usage: sayhi.py [OPTIONS] [NAME]...
Try "sayhi.py --help" for help.
Error: Missing option "-k" / "--keyword".
规避关键词冲突
有些时候,选项名可能会与Python的关键词冲突,如下:
import click
@click.command(help="just say hi")
@click.option("-k", "--keyword", required=True)
@click.option('--from', '-f', 'from_')
@click.argument("name", nargs=-1)
def sayhi(from_, name, keyword):
print(from_, ': hi', keyword, ", ".join(name))
if __name__ == "__main__":
sayhi()
试试执行命令python sayhi.py aber -k ", what are you doing now?"
:
❯ python .\sayhi.py aber -k ", what are you doing now?"
None : hi , what are you doing now? aber
如果稍微敏锐一点,你可能会注意到,函数参数值与位置无关,这是因为click是通过关键词参数传递参数值的。
选项默认值
选项可以被设置默认值,并且在--help
命令下显示出来。
import click
@click.command(help="just say hi")
@click.option("-k", "--keyword", required=True)
@click.option('--from', '-f', 'from_', default="Aber", show_default=True)
@click.argument("name", nargs=-1)
def sayhi(from_, name, keyword):
print(from_, ': hi', keyword, ", ".join(name))
if __name__ == "__main__":
sayhi()
然后看看执行结果:
❯ python .\sayhi.py Sherry -k ", what are you doing now?"
Aber : hi , what are you doing now? Sherry
❯ python .\sayhi.py --help
Usage: sayhi.py [OPTIONS] [NAME]...
just say hi
Options:
-k, --keyword TEXT [required]
-f, --from TEXT [default: Aber]
--help Show this message and exit.
多值选项
同样的,option也提供了nargs
参数用以接收多个值,与参数类似。
多选项值
设置 multiple=True
即可允许接受 -m bob -m sherry
这类选项。
布尔类型选项
click推荐给布尔类型的选项一对值,在修改默认值时会比较方便。
import click
@click.command(help="just say hi")
@click.option("-k", "--keyword", required=True)
@click.option('--from', '-f', 'from_', default="Aber", show_default=True)
@click.option('--debug/--no-debug', default=False)
@click.argument("name", nargs=-1)
def sayhi(from_, name, keyword, debug):
print(debug, from_, ': hi', keyword, ", ".join(name))
if __name__ == "__main__":
sayhi()
执行结果如下:
❯ python .\sayhi.py Sherry -k ", what are you doing now?"
False Aber : hi , what are you doing now? Sherry
❯ python .\sayhi.py Sherry -k ", what are you doing now?" --debug
True Aber : hi , what are you doing now? Sherry
❯ python .\sayhi.py Sherry -k ", what are you doing now?" --no-debug
False Aber : hi , what are you doing now? Sherry
但有些时候,或许只是需要开启或者不开启,而不是需要在开启/关闭状态间显式的指定。
将@click.option('--debug/--no-debug', default=False)
修改为@click.option('--debug', is_flag=True)
。它的执行效果与上面的相同,但不能接受--no-debug
的选项。
组合命令
更多的时候,我们需要构建的命令行程序由多个子命令组成。以pipenv为例,pipenv
本身是一个命令,同时它也拥有众多子命令。
click提供了这样的能力,使用click.group
,这将允许把一些命令挂载主命令下。
把原来的click.command
替换为click.group
,然后加入子命令。
import click
@click.group(help="just say hi")
@click.option("-k", "--keyword", required=True)
@click.option('--from', '-f', 'from_', default="Aber", show_default=True)
@click.option('--debug', is_flag=True)
@click.argument("name", nargs=-1)
def sayhi(from_, name, keyword, debug):
print(debug, from_, ': hi', keyword, ", ".join(name))
@sayhi.command(help="just say bye")
def saybye():
print("bye")
if __name__ == "__main__":
sayhi()
尝试一下 --help
能看到子命令已经成功加入了。
❯ python .\sayhi.py --help
Usage: sayhi.py [OPTIONS] [NAME]... COMMAND [ARGS]...
just say hi
Options:
-k, --keyword TEXT [required]
-f, --from TEXT [default: Aber]
--debug
--help Show this message and exit.
Commands:
saybye just say bye
其他功能
多彩输出
click的secho
函数提供了一个比较好用的输出功能。
click.secho("hello world", fg="green")
fg
可用的选项有:
-
black (可能是灰色)
-
red
-
green
-
yellow (可能是橘色)
-
blue
-
magenta
-
cyan
-
white (可能是亮灰色)
-
bright_black
-
bright_red
-
bright_green
-
bright_yellow
-
bright_blue
-
bright_magenta
-
bright_cyan
-
bright_white
-
reset (重置颜色)
如果不想在最后输出换行符可以设置nl=False
:
click.secho("hello world", fg="red", nl=False)
Prompts(输入)
click.prompts
在默认情况下支持任何unicode输入,但你也可以指定输入类型
value = click.prompt('Please enter a valid integer', type=int)
在提供了默认值时,类型会被自动确定
value = click.prompt('Please enter a number', default=42.0)
更多的功能例如进度条、打开文件、执行文件等,可看click/utils。