地址

Python–Click

  • Click的开发初衷就是使用最少的代码,以一种可组合的方式创建漂亮的命令行接口
  • 它的目的是使编写命令行工具的过程快速而有趣,同时防止由于无法实现预期的CLI API而导致的任何问题。

基本使用

1
2
3
4
5
6
7
8
9
10
11
# demo.py
import click

@click.command()
@click.option("--count", '-c', default=1, help="打印次数", type=int)
def hello(count):
for i in range(count):
click.echo('Hello World!')

if __name__ == '__main__':
hello()

对于上面的代码 , 我们在cmd

  • 执行 python demo.py 就可以返回Hello World!
  • 执行 python demo.py --count 3 就可以打印三个Hello World!
  • -c--count 的简写 , 所以执行 python demo.py --c 3 打印三个Hello World!

方法功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# demo.py
import click

@click.command()
@click.option("--name", default="li", help="your name")
@click.option("--age", default=26, help="your age")
@click.option('--gender', type=click.Choice(['man', 'woman'])) # 限定值
@click.option('--parents', nargs=2, type=string, help='your father and mother')
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True)
def hello_world(name, age):
click.echo(name)
print(age)

hello_world()

方法

  • command:用于装饰一个函数,使得该函数作为命令行的接口,例如上述装饰hello_world
  • option:用于装饰一个函数,主要功能是为命令行添加选项
  • echo:用于输出结果,由于print函数在2.x和3.x之间存在不同之处,为了更好的兼容性,因此提供了echo输出方法

参数

  • default: 设置命令行参数的默认值
  • help: 参数说明
  • type: 参数类型,可以是 string, int, float 等
  • Choice:输入为一个列表,列表中为选项可选择的值
  • prompt: 当在命令行中没有输入相应的参数时,会根据 prompt 提示用户输入
  • nargs: 指定命令行参数接收的值的个数
  • hide_input: 用于隐藏输入(用于输入密码)
  • confirmation_promt: 用于重复输入(用于重复输入密码)
  • metavar:如何在帮助页面表示值

hide_input和confirmation_promt说明

1
2
3
4
5
6
7
8
9
import click

@click.command()
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True)
def input_password(password):
click.echo('password: %s' % password)

if __name__ == '__main__':
input_password()

可以简写成

1
2
3
4
5
6
7
8
9
import click

@click.command()
@click.password_option()
def input_password(password):
click.echo('password: %s' % password)

if __name__ == '__main__':
input_password()

prompt说明

prompt : 有些命令行工具在运行的时候要求用户输入信息,可以给 option 装饰器指定 prompt 参数

1
2
3
4
5
6
7
8
9
10
11
>import click

>@click.command()
>@click.option("--count", default=1, help="打印次数", type=int)
>@click.option("--name", prompt="请输入名字", help="姓名")
>def hello(count, name):
for i in range(count):
click.echo(f'Hello {name}!')

>if __name__ == '__main__':
hello()
1
2
3
4
>$ python click_demo.py

>请输入名字: lzjun
>Hello lzjun!

help说明

help : 执行python demo.py --help , 得到

1
2
3
4
5
6
Usage: demo.py [OPTIONS]

Options:
--name TEXT your name
--age INTEGER your age
--help Show this message and exit.

改变命令行程序的执行

  • 有些参数会改变命令行程序的执行,比如在终端输入 python 是进入 python 控制台,而输入 python --version 是打印 python 版本。
  • Click 提供 eager 标识对参数名进行标识,如果输入该参数,则会拦截既定的命令行执行流程,跳转去执行一个回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import click

def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
click.echo('Version 1.0')
ctx.exit()

@click.command()
@click.option('--version', is_flag=True, callback=print_version,
expose_value=False, is_eager=True)
@click.option('--name', default='Ethan', help='name')
def hello(name):
click.echo('Hello %s!' % name)

if __name__ == '__main__':
hello()
  • is_eager=True 表明该命令行选项优先级高于其他选项;
  • expose_value=False 表示如果没有输入该命令行选项,会执行既定的命令行流程(也就是放弃此选项);
  • callback 指定了输入该命令行选项时,要跳转执行的函数;
1
2
3
4
5
6
7
8
9
10
11
$ python click_eager.py
Hello Ethan!

$ python click_eager.py --version # 拦截既定的命令行执行流程
Version 1.0

$ python click_eager.py --name Michael
Hello Michael!

$ python click_eager.py --version --name Ethan # 忽略 name 选项
Version 1.0

click.argument

  • 使用 @click.option 来添加可选参数
  • 使用 @click.argument 来添加固定参数
  • @click.argument `的使用和 option 类似,但支持的功能比 option 少。
1
2
3
4
5
6
7
8
9
import click

@click.command()
@click.argument('coordinates')
def show(coordinates):
click.echo('coordinates: %s' % coordinates)

if __name__ == '__main__':
show()
1
2
3
4
$ python click_argument.py --coordinates 10    # 错误用法,这是 option 参数的用法
Error: no such option: --coordinates

$ python click_argument.py 10 # 正确,直接输入值即可
1
2
3
4
5
6
7
8
9
10
11
import click

@click.command()
@click.argument('x')
@click.argument('y')
@click.argument('z')
def show(x, y, z):
click.echo('x: %s, y: %s, z:%s' % (x, y, z))

if __name__ == '__main__':
show()
1
2
$ python click_argument.py 10 20 30
x: 10, y: 20, z:30

不定参数

argument 还有另外一种常见的用法,就是接收不定量的参数

1
2
3
4
5
6
7
8
9
10
import click

@click.command()
@click.argument('src', nargs=-1)
@click.argument('dst', nargs=1)
def move(src, dst):
click.echo('move %s to %s' % (src, dst))

if __name__ == '__main__':
move()
  • nargs=-1 表明参数 src 接收不定量的参数值,参数值会以 tuple 的形式传入函数。
  • 如果 nargs 大于等于 1,表示接收 nargs 个参数值,上面的例子中,dst 接收一个参数值。
1
2
3
4
5
$ python click_argument.py file1 trash    # src=('file1',)  dst='trash'
move (u'file1',) to trash

$ python click_argument.py file1 file2 file3 trash # src=('file1', 'file2', 'file3') dst='trash'
move (u'file1', u'file2', u'file3') to trash

Group

Click 通过 group 来创建一个命令行组,也就是说它可以有各种参数来解决相同类别的不同问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import click

@click.group()
def cli():
pass

@click.command()
def initdb():
click.echo('Initialized the database')

@click.command()
def dropdb():
click.echo('Droped the database')

cli.add_command(initdb)
cli.add_command(dropdb)

if __name__ == "__main__":
cli()

执行情况

1
2
3
4
5
6
7
8
9
$ python hello.py
Usage: hello.py [OPTIONS] COMMAND [ARGS]...

Options:
--help Show this message and exit.

Commands:
dropdb
initdb
1
2
$ python hello.py initdb
Initialized the database
1
2
$ python hello.py dropdb
Droped the database