Python3 Click模块的使用方法详解

Click 是 Flask 的团队 pallets 开发的优秀开源项目,它为命令行工具的开发封装了大量方法,使开发者只需要专注于功能实现。恰好我最近在开发的一个小工具需要在命令行环境下操作,就写个学习笔记。

国际惯例,先来一段 “Hello World” 程序(假定已经安装了 Click 包)。

# hello.py
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
       help='The person to greet.')
def hello(count, name):
  """Simple program that greets NAME for a total of COUNT times."""
  for x in range(count):
    click.echo('Hello %s!' % name)
if __name__ == '__main__':
  hello()

执行 python hello.py --count=3,不难猜到控制台的输出结果。除此之外,Click 还悄悄地做了其他的工作,比如帮助选项:

$ python hello.py --help
Usage: hello.py [OPTIONS]
 Simple program that greets NAME for a total of COUNT times.
Options:
 --count INTEGER Number of greetings.
 --name TEXT   The person to greet.
 --help      Show this message and exit.

函数秒变 CLI

从上面的 “Hello World” 演示中可以看出,Click 是通过装饰器来把一个函数方法装饰成命令行接口的,这个装饰器方法就是 `@click.command()`。

import click
@click.command()
def hello():
  click.echo('Hello World!')

`@click.command()装饰器把hello()方法变成了Command对象,当它被调用时,就会执行该实例内的行为。而–help参数就是Command` 对象内置的参数。

不同的 Command 实例可以关联到 group 中。group 下绑定的命令就成为了它的子命令,参考下面的代码:

@click.group()
def cli():
  pass
@click.command()
def initdb():
  click.echo('Initialized the database')
@click.command()
def dropdb():
  click.echo('Dropped the database')
cli.add_command(initdb)
cli.add_command(dropdb)

`@click.group装饰器把方法装饰为可以拥有多个子命令的Group对象。由Group.add_command()方法把Command对象关联到Group对象。 也可以直接用@Group.command装饰方法,会自动把方法关联到该Group` 对象下。

@click.group()
def cli():
  pass
@cli.command()
def initdb():
  click.echo('Initialized the database')
@cli.command()
def dropdb():
  click.echo('Dropped the database')

命令行的参数是不可或缺的,Click 支持对 command 方法添加自定义的参数,由 option() 和 argument() 装饰器实现。

@click.command()
@click.option('--count', default=1, help='number of greetings')
@click.argument('name')
def hello(count, name):
  for x in range(count):
    click.echo('Hello %s!' % name)

打包跨平台可执行程序

通过 Click 编写了简单的命令行方法后,还需要把 .py 文件转换成可以在控制台里运行的命令行程序。最简单的办法就是在文件末尾加上如下代码:

if __name__ == '__main__':
  command()

Click 支持使用 setuptools 来更好的实现命令行程序打包,把源码文件打包成系统中的可执行程序,并且不限平台。一般我们会在源码根目录下创建 setup.py 脚本,先看一段简单的打包代码:

from setuptools import setup
setup(
  name='hello',
  version='0.1',
  py_modules=['hello'],
  install_requires=[
    'Click',
  ],
  entry_points='''
    [console_scripts]
    hello=hello:cli
  ''',
)

留意 entry_points 字段,在 console_scripts 下,每一行都是一个控制台脚本,等号左边的的是脚本的名称,右边的是 Click 命令的导入路径。

详解命令行参数

上面提到了自定义命令行参数的两个装饰器:`@click.option()和@click.argument()`,两者有些许区别,使用场景也有所不同。

总体而言,argument() 装饰器比 option() 功能简单些,后者支持下面的特性:

  • 自动提示缺失的输入;
  • option 参数可以从环境变量中获取,argument 参数则不行;
  • option 参数在 help 输出中有完整的文档,argument 则没有;

而 argument 参数可以接受可变个数的参数值,而 option 参数只能接收固定个数的参数值(默认是 1 个)。

Click 可以设置不同的参数类型,简单类型如 click.STRING,click.INT,click.FLOAT,click.BOOL。

命令行的参数名由 “-short_name” 和 “–long_name” 声明,如果参数名既没有以 “-“ 开头,也没有以 “–” 开头,那么这边变量名会成为被装饰方法的内部变量,而非方法参数。

Option 参数

option 最基础的用法就是简单值变量,option 接收一个变量值,下面是一段示例代码:

@click.command()
@click.option('--n', default=1)
def dots(n):
  click.echo('.' * n)

如果在命令行后面跟随参数 --n=2 就会输出两个点,如果传参数,默认输出一个点。上面的代码中,参数类型没有显示给出,但解释器会认为是 INT 型,因为默认值 1 是 int 值。

有些时候需要传入多个值,可以理解为一个 list,option 只支持固定长度的参数值,即设置后必须传入,个数由 nargs 确定。

@click.command()
@click.option('--pos', nargs=2, type=float)
def findme(pos):
  click.echo('%s / %s' % pos)
findme --pos 2.0 3.0 输出结果就是 2.0 / 3.0

既然可以传入 list,那么 tuple 呢?Click 也是支持的:

@click.command()
@click.option('--item', type=(unicode, int))
def putitem(item):
  click.echo('name=%s id=%d' % item)

这样就传入了一个 tuple 变量,putitem --item peter 1338 得到的输出就是 name=peter id=1338

上面没有设置 nargs,因为 nargs 会自动取 tuple 的长度值。因此上面的代码实际上等同于:

@click.command()
@click.option('--item', nargs=2, type=click.Tuple([unicode, int]))
def putitem(item):
  click.echo('name=%s id=%d' % item)

option 还支持同一个参数多次使用,类似 git commit -m aa -m bb 中 -m 参数就传入了 2 次。option 通过 multiple 标识位来支持这一特性:

@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
  click.echo('\n'.join(message))

有时候,命令行参数是固定的几个值,这时就可以用到 Click.choice 类型来限定传参的潜在值:

# choice
@click.command()
@click.option('--hash-type', type=click.Choice(['md5', 'sha1']))
def digest(hash_type):
  click.echo(hash_type)

当上面的命令行程序参数 --hash-type 不是 md5 或 sha1,就会输出错误提示,并且在 --help 提示中也会对 choice 选项有显示。

如果希望命令行程序能在我们错误输入或漏掉输入的情况下,友好的提示用户,就需要用到 Click 的 prompt 功能,看代码:

# prompt
@click.command()
@click.option('--name', prompt=True)
def hello(name):
  click.echo('Hello %s!' % name)

如果在执行 hello 时没有提供 –name 参数,控制台会提示用户输入该参数。也可以自定义控制台的提示输出,把 prompt 改为自定义内容即可。

对于类似账户密码等参数的输入,就要进行隐藏显示。option 的 hide_input 和 confirmation_promt 标识就是用来控制密码参数的输入:

# password
@click.command()
@click.option('--password', prompt=True, hide_input=True,
       confirmation_prompt=True)
def encrypt(password):
  click.echo('Encrypting password to %s' % password.encode('rot13'))

Click 把上面的操作进一步封装成装饰器 click.password_option(),因此上面的代码也可以简化成:

# password
@click.command()
@click.password_option()
def encrypt(password):
  click.echo('Encrypting password to %s' % password.encode('rot13'))

有的参数会改变命令行程序的执行,比如 node 是进入 Node 控制台,而 node --verion 是输出 node 的版本号。Click 提供 eager 标识对参数名进行标记,拦截既定的命令行执行流程,而是调用一个回调方法,执行后直接退出。下面模拟 click.version_option() 的功能,实现 --version 参数名输出版本号:

# eager
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)
def hello():
  click.echo('Hello World!')

对于类似删除数据库表这样的危险操作,Click 支持弹出确认提示,--yes 标识位置为 True 时会让用户再次确认:

# yes parameters
def abort_if_false(ctx, param, value):
  if not value:
    ctx.abort()
@click.command()
@click.option('--yes', is_flag=True, callback=abort_if_false,
       expose_value=False,
       prompt='Are you sure you want to drop the db?')
def dropdb():
  click.echo('Dropped all tables!')

测试运行下:

$ dropdb
Are you sure you want to drop the db? [y/N]: n
Aborted!
$ dropdb --yes
Dropped all tables!

同样的,Click 对次进行了封装,click.confirmation_option() 装饰器实现了上述功能:

@click.command()
@click.confirmation_option(prompt='Are you sure you want to drop the db?')
def dropdb():
  click.echo('Dropped all tables!')

前面只讲了默认的参数前缀 -- 和 -,Click 允许开发者自定义参数前缀(虽然严重不推荐)。

# other prefix
@click.command()
@click.option('+w/-w')
def chmod(w):
  click.echo('writable=%s' % w)
if __name__ == '__main__':
  chmod()

如果想要用 / 作为前缀,而且要像上面一样采用布尔标识,会产生冲突,因为布尔标识也是用 /,这种情况下可以用 ; 代替布尔标识的 /:

@click.command()
@click.option('/debug;/no-debug')
def log(debug):
  click.echo('debug=%s' % debug)
if __name__ == '__main__':
  log()

既然支持 Choice,不难联想到 Range,先看代码:

# range
@click.command()
@click.option('--count', type=click.IntRange(0, 20, clamp=True))
@click.option('--digit', type=click.IntRange(0, 10))
def repeat(count, digit):
  click.echo(str(digit) * count)
if __name__ == '__main__':
  repeat()

Argument 参数

Argument 的作用类似 Option,但没有 Option 那么全面的功能。

和 Option 一样,Argument 最基础的应用就是传递一个简单变量值:

@click.command()
@click.argument('filename')
def touch(filename):
  click.echo(filename)

命令行后跟的参数值被赋值给参数名 filename。

另一个用的比较广泛的是可变参数,也是由 nargs 来确定参数个数,变量值会以 tuple 的形式传入函数:

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

运行程序:

$ copy foo.txt bar.txt my_folder
move foo.txt to folder my_folder
move bar.txt to folder my_folder

Click 支持通过文件名参数对文件进行操作,click.File() 装饰器就是处理这种操作的,尤其是在类 Unix 系统下,它支持以 - 符号作为标准输入/输出。

# File

@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)
    if not chunk:
      break
    output.write(chunk)

运行程序,先将文本写进文件,再读取

$ inout - hello.txt
hello
^D
$ inout hello.txt -
hello

如果参数值只是想做为文件名而已呢,很简单,将 type 指定为 click.Path():

@click.command()
@click.argument('f', type=click.Path(exists=True))
def touch(f):
  click.echo(click.format_filename(f))
$ touch hello.txt
hello.txt
$ touch missing.txt
Usage: touch [OPTIONS] F
Error: Invalid value for "f": Path "missing.txt" does not exist.

更多关于Python3 Click模块的使用方法请查看下面的相关链接

(0)

相关推荐

  • python命令行工具Click快速掌握

    前言 写 Python 的经常要写一些命令行工具,虽然标准库提供有命令行解析工具 Argparse,但是写起来非常麻烦,我很少会使用它.命令行工具中用起来最爽的就是 Click,它是 Flask 的团队 pallets 的开源项目.Click 只要很少的代码就可以优雅地创造一个命令行工具,它致力于将创建命令行工具的过程变的快速而有趣. 百闻不如一试 安装 pip install Click 使用 创建 click_demo.py ,写一个最简单的函数 import click @click.co

  • Python中强大的命令行库click入门教程

    前言 我们的游戏资源处理工具是Python实现的,功能包括csv解析,UI材质处理,动画资源解析.批处理,Androd&iOS自动打包等功能.该项目是由其他部门继承过来的,由于绝大部分代码不符合我们的业务需求,所以进行了大重构.删除了所有业务代码,仅保留了python代码框架.项目中命令行参数解析是自己实现的,极其不优雅,也忍了这么久.打算找时间用click重写.所以最近学习了click,下面本文的内容是click的入门教程,初学者们可以来一起学习学习. 官网镜像地址: http://click

  • 详解python的argpare和click模块小结

    一.argparse模块 1.模块说明 # argparse是python的标准库中用来解析命令行参数的模块,用来替代已经过时的optparse模块,argparse能够根据程序中的定义的sys.argv中解析出这些参数, # 并自动生成帮助和使用信息 2.模块常用的参数 # 参数说明: # name/flag:参数的名字 # action:遇到参数的动作,默认值是store # nargs:参数的个数,可以是具体的数字,或者是+或者是*,*表示0个或者多个参数,+号表示1个或者多个参数 # d

  • 大家都说好用的Python命令行库click的使用

    一.前言 在本系列前面几篇文章中,我们分别介绍了 argparse 和 docopt 的主要功能和用法.它们各具特色,都能出色地完成命令行任务.argparse 是面向过程的,需要先设置解析器,再定义参数,再解析命令行,最后实现业务逻辑.而 docopt 先用声明式的语法定义出参数,再过程式地解析命令行和实现业务逻辑.在一些人看来,这些方式都不够优雅. 而今天要介绍的 click[2] 则是用一种你很熟知的方式来玩转命令行.命令行程序本质上是定义参数和处理参数,而处理参数的逻辑一定是与所定义的参

  • Python命令行click参数用法解析

    这篇文章主要介绍了Python命令行click参数用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 在概念上, click 把命令行分为 3 个组成:参数.选项和命令. 参数 就是跟在命令后的除选项外的内容,比如 git add a.txt 中的 a.txt 就是表示文件路径的参数 选项 就是以 - 或 -- 开头的参数,比如 -f.--file 命令 就是命令行的初衷了,比如 git 就是命令,而 git add 中的 add

  • Python3 Click模块的使用方法详解

    Click 是 Flask 的团队 pallets 开发的优秀开源项目,它为命令行工具的开发封装了大量方法,使开发者只需要专注于功能实现.恰好我最近在开发的一个小工具需要在命令行环境下操作,就写个学习笔记. 国际惯例,先来一段 "Hello World" 程序(假定已经安装了 Click 包). # hello.py import click @click.command() @click.option('--count', default=1, help='Number of gre

  • 对Python3使运行暂停的方法详解

    在Python3中已经有很大一部分语句与Python2不互通了,运行暂停的方法也有所不同. 1.input(); 这种方法不用包含模块,因此这也是最常用的一种暂停手段. Python2中的raw_input()和input()语句在Python3中已经被合并到input()中. 2.os.system("pause"); 这种方法需要包含os模块(import os),在windows下IDLE运行会弹出cmd命令行, 进行暂停操作,直接运行.py文件会直接在命令行中暂停. 3.tim

  • 关于pip的安装,更新,卸载模块以及使用方法(详解)

    在Python的学习过程中,肯定会遇到很多安装模块的地方,可以使用easy_install安装,但是easy_install相对于pip而言,最大的缺陷就是它所安装的模块是不能够卸载的,其他功能是和pip一样的. 下面介绍一下pip的安装: 安装我总结了两个方法 1 通过下载安装文件来安装 2 通过easy_install安装 1 下载pip安装包 https://pypi.python.org/pypi/pip#downloads 1) 网页提供了两个安装包,一个是.whl的 一个是压缩包的,

  • NodeJs 文件系统操作模块fs使用方法详解

    NodeJs:文件读取API使用方法 - - readFile() 需求:使用Node中提供的文件操作API,读取files目录下的1.txt 文档中文本内容. Node的三个组成部分:ECMAScript核心 + 全局成员 + 核心API成员 核心API成员,在大家安装Node应用程序的时候,就已经安装到了自己的电脑中. 如果想要访问核心成员,直接使用require("核心成员的名称"),就能够导入并使用这些核心成员. const fs = require("fs"

  • Python 常用模块 re 使用方法详解

    一.re模块的查找方法: 1.findall   匹配所有每一项都是列表中的一个元素 import re ret = re.findall('\d+','asd鲁班七号21313') # 正则表达式,待匹配的字符串,flag # ret = re.findall('\d','asd鲁班七号21313') # 正则表达式,待匹配的字符串,flag # print(ret) 2.search 只匹配从左到右的第一个,等到的不是直接的结果,而是一个变量,通过这个变量的group方法来获取结果 impo

  • python3 enum模块的应用实例详解

    一.枚举与字典类型 字典类型的缺点: 1.值可变 2.没有防止相同标签的功能 枚举的特点: 1.枚举类的值不可以被外界更改 2.不能存在相同的标签,但允许不同标签存在相同的枚举值,即后者相当于前者的别名 3.枚举值可以是任意类型 4.枚举标签尽量用大写 from enum import Enum #普通类 class dict(): green = 1 green = 2 red = 3 dict.red = 4 print(dict.red) >>> 4 class VIP(Enum)

  • 基于Layui自定义模块的使用方法详解

    layui是一个极其不错的前端UI框架.是后端程序员的福音.总之如果你是一个后端开发者.如果你苦于你的界面"惨不忍睹".选择layui来开发是个极好的选择. 之前的项目也有使用过layui.只是没有过多的关注其框架本身.对于项目上.拿来即用即可! 为什么要自定义模块呢?好处很多.比如可以大量重用代码...... 我也是一个极其懒惰的人.总是想办法让代码可重用 根据layui官方的文档说明.首先第一步是要确定你要扩展的模块名称 我现在做的是登录功能.因此我的扩展模块名叫 login 使用

  • 对Python3 goto 语句的使用方法详解

    熟悉 C 语言的小伙伴一定对 goto 语句不陌生,它可以在代码之间随意的跳来跳去,但是好多老鸟都告诫大家,不要使用 goto,因为 goto 会使你的代码逻辑变的极其混乱. 但是有时候我们不得不用它,因为它太高效了.比如进入循环内部深层一个 goto 就能回到最上层,还有可以定位到代码的任意一个位置,很是高效方便. 但是也不要所有的代码都用 goto,那样你的代码就变得像量子世界那样诡异,连你自己都控制不了. 最后一句忠告,能不用 goto 最好就不用. 首先安装一个 goto 的包(因为官方

  • Python3内置json模块编码解码方法详解

    目录 JSON简介 dumps编码 编码字典 编码列表 编码字符串 格式化输出JSON 转换关系对照表 loads解码 总结 JSON简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,在接口数据开发和传输中非常常用. Python3中我们利用内置模块json解码和编码JSON对象.jso

  • python随机模块random使用方法详解

    random随机模块包括返回随机数的函数,可以用于模拟或者任何产生随机输出的程序. 一.random模块常用函数介绍 random.random() - 生成一个从0.0(包含)到 1.0(不包含)之间的随机浮点数: random.uniform(a, b) - 生成一个范围为 a≤N≤b 的随机数,随机数类型是浮点数: random.randint(a, b) - 生成一个范围为 a≤N≤b 的随机数,随机数的类型是整形,注意与random.uniform(a, b)区别: random.ra

随机推荐