作者: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. 【CF1137C】 Museums Tour 拆点+缩点

    https://codeforc.es/contest/1137/problem/C # 题意 给你n个点,每个点有k天博物馆开放时间的安排表. 有m条单向道路,走过一条边需要一个晚上,经过后就是第二 ...

  2. CodeForces 821D Okabe and City

    Okabe and City 题解: 将行和列也视为一个点. 然后从普通的点走到行/列的点的话,就代表这行/列已经被点亮了. 然后将费用为0的点建上边. 注意讨论(n,m)非亮的情况下. 代码: #i ...

  3. CF985C Liebig's Barrels 贪心 第二十

    Liebig's Barrels time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  4. 一起来聊一下 JavaScript 的用途和那些特性

    JavaScript 简介 我们一起来聊一下 JavaScript,用它能做什么,它有哪些特性,以及一些跟它配合使用的技术. 什么是 JavaScript? JavaScript 最初的目的是为了&q ...

  5. 基于注解的读取excel的工具包

    easyexcel-wraper easyexcel-wraper是什么? 一个方便读取excel内容,且可以使用注解进行内容验证的包装工具 easyexcel-wraper有哪些功能? 在easye ...

  6. 不权威的国产CPU发展历程

    最近进行了一些国产化相关工作 趁着周末有时间,自己整理一下这段时间的学习内容. 毕竟不是处理器和芯片的业内人士,里面多有纰漏,请谅解. 希望可以作为入门学习的简单知识. 1.0 远古时代 unix 世 ...

  7. Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.catalina.connector.CoyoteWriter and no properties discovered to create BeanSerializer

    一.什么是序列化In computer science, in the context of data storage, serialization is the process of transla ...

  8. SpringBoot 参数校验的方法

    Introduction 有参数传递的地方都少不了参数校验.在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全.试想一下,如果在controller层中没有经过任何校验的参数通过s ...

  9. 【Redis】集群方式

    一.概述 1.1 Redis3.0版本之前 1.2 常见集群方案 二.Redis-Cluster原理 三.搭建集群方案 3.1 准备工作 3.2 创建模拟集群的文件夹 3.3 复制脚本 3.4 复制一 ...

  10. CountDownLatch、CyclicBarrier和Semaphore使用

    CountDownLatch CountDownLatch是用来线程计数的.等待一组线程全部执行完后再本线程继续执行.如:A线程需要等待B.C和D(由初始化CountDownLatch参数觉得等待多少 ...