文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库python
在第一篇“初探 docopt”的文章中,咱们初步掌握了使用 docopt
的三个步骤,了解了它不一样于 argparse
的设计思路。 那么 docopt
的使用模式都有哪些呢?其接口描述中都支持哪些语法规则呢?本文将带你深刻了解 docopt
。git
本系列文章默认使用 Python 3 做为解释器进行讲解。
若你仍在使用 Python 2,请注意二者之间语法和库的使用差别哦~
复制代码
在上一篇文章中咱们提到 docopt
是经过定义一个包含特定内容的字符串,也就是接口描述,来达到描述命令行功能的目的。 那么接口描述的整体规则是这样的:github
usage:
(大小写不敏感)和一个可见的空行之间的文本内容会被解释为一个个使用模式。useage:
后的第一个词会被解释为程序的名称,好比下面就是一个没有命令行参数的示例程序:Usage: cli
复制代码
Usage:
cli command --option <argument>
cli [<optional-argument>]
cli --another-option=<with-argument>
cli (--either-that-option | <or-this-argument>)
cli <repeating-argument> <repeating-argument>...
复制代码
使用 <
和 >
包裹的参数会被解释为位置参数。编程
好比,咱们能够指定两个位置参数 x
和 y
,先添加的 x
位于第一个位置,后加入的 y
位于第二个位置。那么在命令行中输入 1 2
的时候,分别对应到的就是 x
和 y
:bash
""" Usage: cli <x> <y> """
from docopt import docopt
arguments = docopt(__doc__, argv=['1', '2'])
print(arguments)
复制代码
其输出为:函数
{'<x>': '1',
'<y>': '2'}
复制代码
以单个破折号(-
)开头的的参数为短选项,以双破折号(--
)开头的参数为长选项。ui
-abc
等价于 -a
、-b
和 -c
空格
或 =
指定,好比 --input ARG
等价于 --input=ARG
空格
指定,好比 -f FILE
等价于 -fFILE
在下面这个例子中,咱们但愿经过 -n
h 或 --name
来指定名字:this
""" Usage: cli [options] Options: -n, --name NAME Set name. """
from docopt import docopt
arguments = docopt(__doc__, argv=['-n', 'Eric'])
print(arguments)
arguments = docopt(__doc__, argv=['-nEric'])
print(arguments)
arguments = docopt(__doc__, argv=['--name', 'Eric'])
print(arguments)
arguments = docopt(__doc__, argv=['--name=Eric'])
print(arguments)
复制代码
上面的示例中,咱们经过 4 种方式(2 个短选项参数方式和 2 个长选项参数方式)来指定命令行输入,其输出均为:spa
{'--name': 'Eric'}
复制代码
须要注意的是:命令行
--input ARG
(而不是 --input=ARG
)的含义是模糊不清的,由于这不能看出 ARG
到底是选项参数, 仍是位置参数。在 docopt
的使用模式中,只有在接口描述中定义了对应选项才会被解释为一个带参数的选项, 不然就会被解释为一个选项和一个独立的位置参数。
-f FILE
和 -fFILE
这种写法也有一样的模糊点。后者没法说明这到底是一系列短选项的集合, 仍是一个带参数的选项。只有在接口描述中定义了对应选项才会被解释为一个带参数的选项。
这里的命令也就是 argparse
中嵌套解析器所要完成的事情,准确的说,对整个命令行程序来讲,实现的是子命令。
在 docopt
中,凡是不符合 --options
或 <arguments>
约定的词,均会被解释为子命令。
在下面这个例子中,咱们支持 create
和 delete
两个子命令,用来建立或删除指定路径。而 delete
命令支持 --recursive
参数来代表是否递归删除指定路径:
""" Usage: cli create cli delete [--recursive] Options: -r, --recursive Recursively remove the directory. """
from docopt import docopt
arguments = docopt(__doc__)
print(arguments)
复制代码
直接指定 delete -r
,输出以下:
$ python3 cli.py delete -r
{'--recursive': True,
'create': False,
'delete': True}
复制代码
以中括号“[]”包裹的元素(选项、参数和命令)均会被标记为可选。多个元素放在一对中括号中或各自放在中括号中是等价的。好比:
Usage: cli [command --option <argument>]
复制代码
等价于:
Usage: cli [command] [--option] [<argument>]
复制代码
没被中括号“[]”包裹的全部元素默认都是必填的。但有时候使用小括号“()”将元素包裹住,用以标记必填是有必要的。 好比,要将多个互斥元素进行分组:
Usage: my_program (--either-this <and-that> | <or-this>)
复制代码
另外一个例子是,当出现一个参数时,也要求提供另外一个参数,那么就能够这么写:
Usage: my_program [(<one-argument> <another-argument>)]
复制代码
这个例子中 <one-argument>
和 <another-argument>
要么都出现,要么都不出现。
在 argparse
中要想实现互斥参数,还须要先调用 parser.add_mutually_exclusive_group()
添加互斥组, 再在组里添加参数。而在 docopt
中就特别简单,直接使用 |
进行分隔:
Usage: my_program go (--up | --down | --left | --right)
复制代码
在上面的示例中,使用小括号“()”来对四个互斥选项分组,要求必填其中一个选项。 在下面的示例中,使用中括号“()”来对四个互斥选项分组,能够不填,或填其中一个选项:
Usage: my_program go [--up | --down | --left | --right]
复制代码
咱们还能够发散一下思路,子命令自然须要互斥,那么除了这种写法:
Usage: my_program run [--fast]
my_program jump [--high]
复制代码
使用以下 |
的写法,也是等价的:
Usage: my_program (run [--fast] | jump [--high])
复制代码
可变参数列表也就是定义参数能够有多个值。在 argparse
中,咱们经过 parser.add_argument('--foo', nargs='?')
来指定,其中 nargs
能够是数字、?
、+
、*
来表示参数个数。
在 docopt
中,天然也有相同的能力,使用省略号 ...
来实现:
Usage: my_program open <file>...
my_program move (<from> <to>)...
复制代码
若要参数提供 N 个,则写 N 个参数便可,好比下面的示例中要求提供 2 个:
Usage: my_program <file> <file>
复制代码
若要参数提供 0 个或多个,则配合中括号“[]”进行定义,以下 3 中定义方式等价:
Usage: my_program [<file>...]
my_program [<file>]...
my_program [<file> [<file> ...]]
复制代码
若要参数提供 1 个或多个,则能够这么写:
Usage: my_program <file>...
复制代码
在下面完整示例中,所得到的 arguments
是 {'<file>': ['f1', 'f2']}
:
""" Usage: cli <file>... """
from docopt import docopt
arguments = docopt(__doc__, argv=['f1', 'f2'])
print(arguments)
复制代码
“[options]”用于简写选项,好比下面的示例中定义了 3 个选项:
Usage: my_program [--all --long --human-readable] <path>
--all List everything.
--long Long output.
--human-readable Display in human-readable format.
复制代码
能够简写为:
Usage: my_program [options] <path>
--all List everything.
--long Long output.
--human-readable Display in human-readable format.
复制代码
若是一个模式中有多个选项,那么这会颇有用。
另外,若是选项包含长短选项,那么也能够用它们中的任意一个写在模式中,好比下面的示例的模式中均使用短选项:
Usage: my_program [-alh] <path>
-a, --all List everything.
-l, --long Long output.
-h, --human-readable Display in human-readable format.
复制代码
当双破折号“--”不是选项时,一般用于分隔选项和位置参数,以便处理例如将文件名误认为选项的状况。 为了支持此约定,须要在位置参数前添加 [--]
。
Usage: my_program [options] [--] <file>...
复制代码
当单破折号“-”不是选项时,一般用于表示程序应处理 stdin
,而非文件。为了支持此约定,须要在使用模式中加入 [-]
。
选项描述就是描述一系列选项参数的模式。若是使用模式中的选项定义是清晰的,那么选项描述就是可选的。
选项描述能够定义以下内容:
选项描述的每一行须要以 -
或 --
开头(不算空格),好比:
Options:
--verbose # 好
-o FILE # 好
Other: --bad # 坏, 没有以 "-" 开头
复制代码
选项描述中,使用空格或“=”来链接选项和参数,以定义带选项的参数。参数可使用 <Arg>
的形式, 或是使用 ARG
大写字母的形式。可用逗号“,”来分隔长短选项。好比:
-o FILE --output=FILE # 没有逗号 长选项使用 "=" 分隔
-i <file>, --input <file> # 有逗号, 长选项使用空格分隔
复制代码
选项描述中每一个选项定义和说明之间要有两个空格,好比:
--verbose MORE text. # 坏, 会被认为是带参数 MORE 的选项
# --version 和 MORE text. 之间应该有2个空格
-q Quit. # 好
-o FILE Output file. # 好
--stdout Use stdout. # 好,2个空格
复制代码
选项描述中在说明中使用 [default: <default-value>]
来给带参数的选项赋以默认值,好比:
--coefficient=K The K coefficient [default: 2.95]
--output=FILE Output file [default: test.txt]
--directory=DIR Some directory [default: ./]
复制代码
关于 docopt
的方方面面咱们都了解的差很少了,回过头来看。对于命令行元信息的定义,它比 argparse
要来的更加简洁。
argparse
像是命令式编程,调用一个个的函数逐步将命令行元信息定义清楚;而 docopt
则像是声明式编程,经过声明定义命令行元信息。
二者站在的维度不一样,编程的套路也不尽相同,甚是有趣。
了解了这么多,也该练练手了。在下篇文章中,咱们仍然会以 git
命令做为实战项目,看看如何使用 docopt
来实现 git
命令。
『讲解开源项目系列』——让对开源项目感兴趣的人再也不畏惧、让开源项目的发起者再也不孤单。跟着咱们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系咱们、加入咱们,让更多人爱上开源、贡献开源~