python argparse_Python 命令行之旅:argparse、docopt、click 和 fire 总结篇

本文首发于HelloGitHub公众号,并发表于Prodesire 博客。

一、前言

在近半年的 Python 命令行旅程中,我们依次学习了 argparsedocoptclickfire 库的特点和用法,逐步了解到 Python 命令行库的设计哲学与演变。 本文作为本次旅程的终点,希望从一个更高的视角对这些库进行横向对比,总结它们的异同点和使用场景,以期在应对不同场景时能够分析利弊,选择合适的库为己所用。

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

二、设计理念

在讨论各个库的设计理念之前,我们先设计一个计算器程序,其实这个例子在 argparse 库的第一篇讲解中出现过,也就是:

  • 命令行程序接受一个位置参数,它能出现多次,且是数字
  • 默认情况下,命令行程序会求出给定的一串数字的最大值
  • 如果指定了选项参数 --sum,那么就会将求出给定的一串数字的和

希望从各个库实现该例子的代码中能进一步体会它们的设计理念。

2.1、argparse

argparse 的设计理念就是提供给你最细粒度的控制,你需要详细地告诉它参数是选项参数还是位置参数、参数值的类型是什么、该参数的处理动作是怎样的。 总之,它就像是一个没有智能分析能力的初代机器人,你需要告诉它明确的信息,它才会根据给定的信息去帮助你做事情。

以下示例为 argparse 实现的 计算器程序

import argparse# 1. 设置解析器
parser = argparse.ArgumentParser(description='Calculator Program.')# 2. 定义参数
# 添加位置参数 nums,在帮助信息中显示为 num
# 其类型为 int,且支持输入多个,且至少需要提供一个
parser.add_argument('nums',  metavar='num', type=int, nargs='+',help='a num for the accumulator')
# 添加选项参数 --sum,该参数被 parser 解析后所对应的属性名为 accumulate
# 若不提供 --sum,默认值为 max 函数,否则为 sum 函数
parser.add_argument('--sum', dest='accumulate', action='store_const',const=sum, default=max,help='sum the nums (default: find the max)')# 3. 解析参数
args = parser.parse_args(['--sum', '1', '2', '3'])
print(args) # 结果:Namespace(accumulate=<built-in function sum>, nums=[1, 2, 3])# 4. 业务逻辑
result = args.accumulate(args.nums)
print(result)  # 基于上文的 ['--sum', '1', '2', '3'] 参数,accumulate 为 sum 函数,其结果为 6

从上述示例可以看到,我们需要通过 add_argument 很明确地告诉 argparse 参数长什么样:

  • 它是位置参数 nums,还是选项参数 --sum
  • 它的类型是什么,比如 type=int 表示类型是 int
  • 这个参数能重复出现几次,比如 nargs='+' 表示至少提供 1 个
  • 参数的是存什么的,比如 action='store_const' 表示存常量

然后它才根据给定的这些元信息来解析命令行参数(也就是示例中的 ['--sum', '1', '2', '3'])。

这是很计算机的思维,虽然冗长,但也带来了灵活性。

2.2、docopt

argparse 的理念可以看出,它是命令式的。这时候 docopt 另辟蹊径,声明式是不是也可以?一个命令行程序的帮助信息其实已然包含了这个命令行的完整元信息,那不就可以通过定义帮助信息来定义命令行?docopt 就是基于这样的想法去设计的。

声明式的好处在于只要你掌握了声明式的语法,那么定义命令行的元信息就会很简单。

以下示例为 docopt 实现的 计算器程序

# 1. 定义接口描述/帮助信息
"""Calculator Program.Usage:calculator.py [--sum] <num>...calculator.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, argv=['--sum', '1', '2', '3'])
print(arguments) # 结果:{'--help': False, '--sum': True, '<num>': ['1', '2', '3']}# 3. 业务逻辑
nums = (int(num) for num in arguments['<num>'])if arguments['--sum']:result = sum(nums)
else:result = max(nums)print(result) # 基于上文的 ['--sum', '1', '2', '3'] 参数,处理函数为 sum 函数,其结果为 6

从上述示例可以看到,我们通过 __doc__ 定义了接口描述,这和 argparseadd_argument 是等价的,然后 docopt 便会根据这个元信息把命令行参数转换为一个字典。业务逻辑中就需要对这个字典进行处理。

对比与 argparse

  • 对于更为复杂的命令程序,元信息的定义上 docopt 会更加简单
  • 然而在业务逻辑的处理上,由于 argparse 在一些简单参数的处理上会更加便捷(比如示例中的情形),相对来说 docopt 转换为字典后就把所有处理交给业务逻辑的方式会更加复杂

2.3、click

命令行程序本质上是定义参数和处理参数,而处理参数的逻辑一定是与所定义的参数有关联的。那可不可以用函数和装饰器来实现处理参数逻辑与定义参数的关联呢?而 click 正好就是以这种使用方式来设计的。

click 使用装饰器的好处就在于用装饰器优雅的语法将参数定义和处理逻辑整合在一起,从而暗示了路由关系。相比于 argparsedocopt 需要自行对解析后的参数来做路由关系,简单了不少。

以下示例为 click 实现的 计算器程序

import sys
import clicksys.argv = ['calculator.py', '--sum', '1', '2', '3']# 2. 定义参数
@click.command()
@click.argument('nums', nargs=-1, type=int)
@click.option('--sum', 'use_sum', is_flag=True, help='sum the nums (default: find the max)')
# 1. 业务逻辑
def calculator(nums, use_sum):"""Calculator Program."""print(nums, use_sum) # 输出:(1, 2, 3) Trueif use_sum:result = sum(nums)else:result = max(nums)print(result) # 基于上文的 ['--sum', '1', '2', '3'] 参数,处理函数为 sum 函数,其结果为 6calculator()

从上述示例可以看出,参数和对应的处理逻辑非常好地绑定在了一起,看上去就很直观,使得我们可以明确了解参数会怎么处理,这在有大量参数时显得尤为重要,这边是 click 相比于 argparsedocopt 最明显的优势。

此外,click 还内置了很多实用工具和额外能力,比如说 Bash 补全、颜色、分页支持、进度条等诸多实用功能,可谓是如虎添翼。

2.4、fire

fire 则是用一种面向广义对象的方式来玩转命令行,这种对象可以是类、函数、字典、列表等,它更加灵活,也更加简单。你都不需要定义参数类型,fire 会根据输入和参数默认值来自动判断,这无疑进一步简化了实现过程。

以下示例为 fire 实现的 计算器程序

import sys
import firesys.argv = ['calculator.py', '1', '2', '3', '--sum']builtin_sum = sum# 1. 业务逻辑
# sum=False,暗示它是一个选项参数 --sum,不提供的时候为 False
# *nums 暗示它是一个能提供任意数量的位置参数
def calculator(sum=False, *nums):"""Calculator Program."""print(sum, nums) # 输出:True (1, 2, 3)if sum:result = builtin_sum(nums)else:result = max(nums)print(result) # 基于上文的 ['1', '2', '3', '--sum'] 参数,处理函数为 sum 函数,其结果为 6fire.Fire(calculator)

从上述示例可以看出,fire 提供的方式无疑是最简单、并且最 Pythonic 的了。我们只需关注业务逻辑,而命令行参数的定义则和函数参数的定义融为了一体。

不过,有利自然也有弊,比如 nums 并没有说是什么类型,也就意味着输入字符串'abc'也是合法的,这就意味着一个严格的命令行程序必须在自己的业务逻辑中来对期望的类型进行约束。

三、横向对比

最后,我们横向对比下argparsedocoptclickfire 库的各项功能和特点:

f005e76217c7aec98d203932bf944f4a.png

Python 的命令行库种类繁多、各具特色。结合上面的总结,可以选择出符合使用场景的库,如果几个库都符合,那么就根据你更偏爱的风格来选择。这些库都很优秀,其背后的思想很是值得我们学习和扩展。

相关文章

  • Python 命令行之旅:初探 argparse
  • Python 命令行之旅:深入 argparse (一)
  • Python 命令行之旅:深入 argparse(二)
  • Python 命令行之旅:使用 argparse 实现 git 命令
  • Python 命令行之旅:初探 docopt
  • Python 命令行之旅:深入 docopt
  • Python 命令行之旅:使用 docopt 实现 git 命令
  • Python 命令行之旅:初探 click
  • Python 命令行之旅:深入 click 之参数篇
  • Python 命令行之旅:深入 click 之选项篇
  • Python 命令行之旅:深入 click 之命令篇
  • Python 命令行之旅:深入 click 之增强功能
  • Python 命令行之旅:使用 click 实现 git 命令
  • Python 命令行之旅:初探 fire
  • Python 命令行之旅:深入 fire(一)
  • Python 命令行之旅:深入 fire(二)
  • Python 命令行之旅:fire 实现 git 命令
  • Python 命令行之旅:argparse、docopt、click 和 fire 总结篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阻塞式和非阻塞式udp传输_NIO非阻塞网络编程三大核心理念

本次开始NIO网络编程&#xff0c;之前已经说过BIO&#xff0c;对于阻塞IO里面的问题一定有了清晰的认识&#xff0c;在JDK1.4版本后&#xff0c;提供了新的JAVA IO操作非阻塞API&#xff0c;用意替换JAVA IO 和JAVA NetWorking相关的API。NIO其实有个名称叫new IO。(一)NIO① 介…

如何查看服务器文件进程,如何查看服务器上的所有进程

如何查看服务器上的所有进程 内容精选换一换华为云SSL证书管理服务帮助中心&#xff0c;为用户提供产品简介、用户指南、常见问题等技术文档&#xff0c;帮助您快速上手使用云证书管理服务。分析辅助软件是一款支持部署到多台服务器目标环境上&#xff0c;实现对整个业务集群的…

python minimize_Python数学规划案例一

Python数学规划案例一问题、模型、数据、算法、结果&#xff0c;统一地表述&#xff0c;是习惯也是效率。我的公众号数学规划模型表述习惯采用五个部分&#xff1a;Set, Data, Variable, Objective, Constraints&#xff1b;每个Notation&#xff0c;采用一个主字符&#xff0c…

java map转string_【库学科技】32道常见的Java基础面试题

内容来源于图灵 侵删。什么是 Java 虚拟机(JVM)&#xff1f;为什么 Java 被称作是“平台无关的编程语言”&#xff1f;Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件。Java 被设计成允许应用程序可以运行在任意的平…

cout输出字符串_leetcode C++题解系列-042 字符串相乘

题目给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。示例 1:输入: num1 "2", num2 "3"输出: "6"示例 2:输入: num1 "123", num2 "456&quo…

python序列类型举例说明_Python(第八课,序列类型)

引言&#xff1a; 我们之前学过整数&#xff0c;浮点数&#xff0c;字符串&#xff0c;今天带来的更具有包容性。 今天带来的是高级数据类型&#xff0c;包括列表&#xff0c;元组&#xff0c;集合和字典。根据他们特性不同&#xff0c;可以分为序列类型&#xff0c;集合类型&a…

上传附件_留学落户|上传附件预审时一定一定要注意的问题!

点击上方蓝色字体&#xff0c;关注启铭君。www.minqifudao.com启铭君相信大家都知道&#xff0c;从2019年留学落户“一网通办”新系统上线&#xff0c;可以在网上进行材料申报&#xff0c;“让数据多走路&#xff0c;让群众少跑腿”。在新系统中填报资料&#xff0c;怎样才能做…

python斐波那契数列30_python的30个骚操作

1、冒泡排序2、计算x的n次方的方法3、计算a*a b*b c*c ……4、计算阶乘 n!5、列出当前目录下的所有文件和目录名6、把一个list中所有的字符串变成小写&#xff1a;7、输出某个路径下的所有文件和文件夹的路径8、输出某个路径及其子目录下的所有文件路径9、输出某个路径及其子…

python中值滤波介绍_Python 实现中值滤波、均值滤波的方法

红包&#xff1a;Lena椒盐噪声图片&#xff1a;# -*- coding: utf-8 -*- """ Created on Sat Oct 14 22:16:47 2017 author: Don """ from tkinter import * from skimage import io import numpy as np imio.imread(lena_sp.jpg, as_greyTrue) …

竖向图片插入_Word小技巧:让你的图片文字排版更有创意

想在头条中发表文章或者写论文&#xff0c;插入的图片太单调&#xff1f;今天小编就简单跟大家分享几个小技巧&#xff0c;图片搭配文字让你的版面更有可读性。第一种&#xff1a;最简单的横向文字排版具体做法&#xff1a;在word中插入图片后&#xff0c;插入一个文本框后输入…

11有没有压力感应_特殊感应器赋予机械手多维触感

最新研发的机械触感装备&#xff0c;已经不仅具有可伸展的韧性&#xff0c;还具有感知压力、形变和拉力的功能&#xff0c;将为软体机器人、虚拟现实(VR)和现实增强(AR)等设备带来革命性的巨变。美国康乃尔大学(Cornell University)工程学院副教授谢泼德(Rob Shepherd)说&#…

如何用手机打开dcm格式图片_如何防止自己的图片被盗用?这 4 招教你优雅加水印...

出门旅游一趟&#xff0c;好不容易拍到一组相当满意的图片。想要把这些图片上传到社交平台&#xff0c;如何才能让大家一看就知道这是自己拍的作品&#xff0c;同时又防止盗图呢&#xff1f;答案是在图片上加上自己的水印&#xff0c;这次有用功将和大家分享下&#xff0c;如何…

python 堆_面试再问你什么是堆和栈,你就把这篇文章甩给他

栈&#xff1a;管程序如何运行的&#xff0c;程序如何执行&#xff0c;如何处理数据。(局部变量其实也是存在栈中的&#xff0c;引用数据类型在栈中存的是地址引用)(栈的空间就不需要那么大了)堆&#xff1a;管数据存储的。(引用数据类型的存放,所以堆的空间是比较大的)生活理解…

3d 仪表盘_新一代标致2008官图发布 配备3D全息仪表盘

【太平洋汽车网 新车频道】标致发布了新一代2008的官图&#xff0c;新车基于PSA集团的CMP平台打造&#xff0c;采用了标致最新一代的家族式设计语言&#xff0c;造型风格极具辨识度。据悉&#xff0c;新一代2008将提供汽油、柴油和纯电动三种动力版本供消费者选择&#xff0c;其…

python人脸识别程序如何嵌入到app_只用Python就能写安卓,简单几步实现人脸识别的App...

最近闲来无事&#xff0c;研究研究在安卓上跑Python。 想起以前玩过的kivy技术&#xff0c;kivy[1]是一个跨平台的UI框架。当然对我们最有用的是&#xff0c;kivy可以把python代码打包成安卓App。但是由于安卓打包的工具链很长&#xff0c;包括android sdk打包java代码、ndk编译…

object htmldivelement什么意思_深入探究 Function amp; Object 鸡蛋问题

&#xff08;给前端树加星标&#xff0c;提升前端技能&#xff09;转自&#xff1a;高级前端进阶引言上篇文章用图解的方式向大家介绍了原型链及其继承方案&#xff0c;在介绍原型链继承的过程中讲解原型链运作机制以及属性遮蔽等知识&#xff0c;今天这篇文章就来深入探究下 F…

如何拉取k8s镜像_K8s 从懵圈到熟练 – 镜像拉取这件小事

导读&#xff1a;相比 K8s 集群的其他功能&#xff0c;私有镜像的自动拉取&#xff0c;看起来可能是比较简单的。而镜像拉取失败&#xff0c;大多数情况下都和权限有关。所以&#xff0c;在处理相关问题的时候&#xff0c;我们往往会轻松的说&#xff1a;这问题很简单&#xff…

hadoop没有datanode_Hadoop运行在Kubernetes平台实践

Hadoop与Kubernetes就好像江湖里的两大绝世高手&#xff0c;一个是成名已久的长者&#xff0c;至今仍然名声远扬&#xff0c;一个则是初出茅庐的青涩少年&#xff0c;骨骼惊奇&#xff0c;不走寻常路&#xff0c;一出手便惊诧了整个武林。Hadoop与Kubernetes之间有很深的渊源&a…

git 修改commit_Git从8到13 深入了解Git特性

上一章简单的介绍了一些常用的Git命令&#xff0c;这一章主要是深入了解一下Git的稍微高级的一些知识和指令。8.首先我们先来通过查看Git目录里面的文件来深入了解一下Git版本控制的构造。 查看HEAD可以知道当前所在的分支。在config文件里面存储着Git里面的一些配置信息&#…

eclipse maven打包jar 部分jsp无法访问_Maven系列教材 (九)- 在Eclipse中创建maven风格的java web项目...

Maven系列教材 &#xff08;九&#xff09;- 在Eclipse中创建maven风格的java web项目步骤1:删除j2ee目录步骤2:新建Maven 项目步骤3:这个界面点下一步步骤4: 这个界面使用webapp&#xff0c;点下一步 步骤5:这一步填写如图所示的信息步骤6:此时得到的maven web 项目的问题步骤…