作者:HelloGitHub-Prodesire

HelloGitHub 的《讲解开源项目》系列,项目地址:https://github.com/HelloGitHub-Team/Article

一、前言

在本系列前面四篇文章中,我们介绍了 argparse 的方方面面。它无疑是强大的,但使用方式上略显麻烦。需要先设置解析器,再定义参数,再解析命令行,最后实现业务逻辑。

而今天要介绍的 docopt 则是站在一个全新的视角来审视命令行。你可曾想过,一个命令行程序的帮助信息其实已然包含了这个命令行的完整元信息,那么是否可以通过定义帮助信息来定义命令行呢?docopt 就是基于这样的想法去设计的。

本系列文章默认使用 Python 3 作为解释器进行讲解。
若你仍在使用 Python 2,请注意两者之间语法和库的使用差异哦~

二、介绍

docopt 基于长久以来在帮助信息和手册中描述程序接口的约定,其接口描述是形式化的帮助信息。它能够根据命令行程序中定义的接口描述,来自动生成解析器。

三、快速开始

3.1 定义接口描述/帮助信息

第一步要做的就是命令行程序的定义接口描述或者是帮助信息,这样 docopt 就能知道命令行的元信息,从而自动解析。

接口描述通常定义在一个模块的文档字符串中,我们仍然以在 Python 命令行之旅:初探 argparse 的例子为例,讲解如何使用 docopt 来定义接口描述。

cmd.py 中,我们定义如下接口描述:

"""Num accumulator.

Usage:
cmd.py [--sum] <num>...
cmd.py (-h | --help) Options:
-h --help Show help.
--sum Sum the nums (default: find the max).
"""

在上面的接口描述中,我们定义了命令行程序 cmd.py 接受一个或多个数字 num,而 --sum 选项则是可选,-h--help 则输出帮助信息。

若提供 --sum,则累加给定的数字;反之,取给定多个数字中最大的一个。这个业务逻辑我们将在后文实现。

3.2 解析命令行

定义好接口描述后,就可以使用 docopt 进行解析,写法非常简单:

from docopt import docopt

arguments = docopt(__doc__, options_first=True)
print(arguments)

由于我们之前是将接口描述定义在模块的文档字符串中,那么直接使用 __doc__ 即可获得接口描述。然后使用 docopt 函数即可解析命令行为参数字典。为了支持负数,我们将 options_first 设置为 True

当我们执行 python3 cmd.py --sum 1 2 3 时,将会得到如下内容:

{'--help': False,
'--sum': True,
'<num>': ['1', '2', '3']}

可以看到:

  • 没有提供 -h 或者 --help,所以 arguments--helpFalse
  • 提供了 --sum,所以 arguments--sumTrue
  • 提供了 <num>...1 2 3,所以 arguments<num>['1', '2', '3']

3.3 业务逻辑

获得了解析后的命令行参数,我们就可以根据自己的业务需求做进一步处理了。

在本文示例中,我们希望当用户提供 --sum 选项时,是对给定的一组数字求和;反之则是取最大值,那么就可以这么写:

nums = (int(num) for num in arguments['<num>'])

if arguments['--sum']:
result = sum(nums)
else:
result = max(nums) print(result) # 基于上文的 python3 cmd.py --sum 1 2 3 参数,其结果为 6

3.4 代码梳理

使用 docopt 的方式非常简单,我们将上文的代码汇总下,以有一个更清晰的认识:

# cmd.py
# 1. 定义接口描述
"""Num accumulator. Usage:
cmd.py [--sum] <num>...
cmd.py (-h | --help) Options:
-h --help Show help.
--sum Sum the nums (default: find the max).
""" from docopt import docopt # 2. 解析命令行
arguments = docopt(__doc__, options_first=True) # 3. 业务逻辑
nums = (int(num) for num in arguments['<num>']) if arguments['--sum']:
result = sum(nums)
else:
result = max(nums) print(result)

若我们需要对一组数字求和,只需执行:

$ python3 cmd.py --sum 1 0 -1
0

若我们需要对一组数字求最大值,只需执行:

$ python3 cmd.py 1 0 -1
1

我们还可以通过 -h--help 参数查看使用说明和帮助,也就是我们定义的接口描述。

四、小节

docopt 的思路非常简单,就是定义接口描述,然后帮你解析命令行为参数字典,接下来就根据这个字典来编写业务逻辑。

重点就是在于如何定义接口描述,在下一篇文章中,我们来深入了解下如何定义命令、选项、位置参数等接口描述。


『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源~

让你如绅士般基于描述编写 Python 命令行工具的开源项目:docopt的更多相关文章

  1. 让你如“老”绅士般编写 Python 命令行工具的开源项目:docopt

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  2. 个推Node.js 微服务实践:基于容器的一站式命令行工具链

    作者:个推Node.js 开发工程师 之诺 背景与摘要 由于工程数量的快速增长,个推在实践基于 Node.js 的微服务开发的过程中,遇到了如下问题: 1. 每次新建项目都需要安装一次依赖,这些依赖之 ...

  3. xterm.js 基于websocket 链接容器 命令行工具

    <template> <div> <el-dialog title="命令" :visible.sync="dialogTableVisib ...

  4. 10. 通过 Dockerfile 编写 linux 命令行工具

    测试 linux 压力的工具 一. 实际操作 1. 创建一个 ubuntu 的容器 docker run -it ubuntu 2. 安装 stress 工具 apt-get update & ...

  5. 如何创建一个基于命令行工具的跨平台的 NuGet 工具包

    命令行可是跨进程通信的一种非常方便的手段呢,只需启动一个进程传入一些参数即可完成一些很复杂的任务.NuGet 为我们提供了一种自动导入 .props 和 .targets 的方法,同时还是一个 .NE ...

  6. nodejs 编写(添加时间戳)命令行工具 timestamp

    Nodejs除了编写服务器端程序还可以编写命令行工具,如gulp.js就是Nodejs编写的. 接下来我们来实现一个添加时间戳的命令: $ timestamp action https://www.n ...

  7. 如何用Node编写命令行工具

    0. 命令行工具 当全局安装模块之后,我们可以在控制台下执行指定的命令来运行操作,如果npm一样.我把这样的模块称之为命令行工具模块(如理解有偏颇,欢迎指正) 1.用Node编写命令行工具 在Node ...

  8. Node.js 命令行工具的编写

    日常开发中,编写 Node.js 命令行工具来完成一些小任务是很常见的操作.其编写也不难,和日常编写 Node.js 代码并无二致. package.json 中的 bin 字段 一个 npm 模块, ...

  9. 使用.Net Core编写命令行工具(CLI)

    命令行工具(CLI) 命令行工具(CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行. 通常认为,命令行工具(CLI)没有 ...

随机推荐

  1. HDU-5977 - Garden of Eden 点分治

    HDU - 5977 题意: 给定一颗树,问树上有多少节点对,节点对间包括了所有K种苹果. 思路: 点分治,对于每个节点记录从根节点到这个节点包含的所有情况,类似状压,因为K<=10.然后处理每 ...

  2. HDU 4565 So Easy! 广义斐波拉数 数论 (a+sqrt(b))^n%mod 模板

    So Easy! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  3. [DP]最长公共子串

    题目 给定两个字符串str1和str2, 长度分别稳M和N,返回两个字符串的最长公共子串 解法一 这是一道经典的动态规划题,可以用M*N的二维dp数组求解.dp[i][j]代表以str1[i]和str ...

  4. 【Offer】[37] 【序列化二叉树】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树. 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得 ...

  5. docker 搭建小型的node开发环境。

    选择daocloud的镜像源----快.不多说 镜像的准备: docker pull docker.io/node 下载node镜像 docker pull daocloud.io/nginx 下载n ...

  6. SpringBoot系列__02HelloWorld探究

    在前文中,我们创建了一个简单的hello world,现在,利用这个简单的程序,来简单分析一下SpringBoot的启动过程. 如果你是使用过SSM框架的人,尤其是4.0之前的版本,相信你使用过xml ...

  7. MyBatis中#{}和${}的区别详解

    首先看一下下面两个sql语句的区别: <select id="selectByNameAndPassword" parameterType="java.util.M ...

  8. 如何让基于.NET 2.0的应用在高版本的系统上运行?

    我们的WinForm项目是基于.NET 2.0开发的,在部署时,发现有些机器没有.NET 2.0,但是即使这些机器有装.NET 2.0 以上的版本,也无法运行我们的程序.这就比较蛋疼了. 我们查了一下 ...

  9. .Net基础篇_学习笔记_第六天_for循环的几个练习

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. Winform中自定义xml配置文件,并配置获取文件路径

    场景 在Winform程序中,需要将一些配置项存到配置文件中,这时就需要自定义xml的配置文件格式.并在一些工具类中去获取配置文件的路径并加载其内容. 关注公众号霸道的程序猿获取编程相关电子书.教程推 ...