python 全网最优雅命令行参数解析, 没有之一

2023-09-21 01:13:37

背景

我们在编写python程序时,程序中经常会提供多种功能或者模式,在实际使用时根据不同的参数使用不同的功能。那么如何获取命令行传入进来的参数呢?

一般方法

一般情况下,我们会使用 sys 模块,如👇

import sys

# 打印 sys 模块获取到的命令行参数
print(sys.argv)

或者,我们会使用 getopt 模块,如👇

import getopt

opts,args=getopt.getopt(sys.argv[1:],"i:ho:",["help","input=","output="])
# 打印选项列表
print(opts)
# 打印参数值列表
print(args)

# 解析参数对应的值
for opts,arg in opts:
	print(opts)
	if opts=="optName":
		print("optName is value is:", arg)

再或者,我们使用 argparse 模块,如👇

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-a', '--arg1', help='argument 1')
parser.add_argument('-b', '--arg2', help='argument 2')
parser.add_argument('-c', '--arg3', help='argument 3')

args = parser.parse_args()

print(args.arg1)
print(args.arg2)
print(args.arg3)

但,以👆这些,都不优雅,如果我们需要在不同的函数或者模块中传递使用命令行进来的参数,那这些零散的参数处理代码,将会带来不小的麻烦。我们需要通过一个专门的类来封装命令行的参数。

引入 DebugInfo 模块

pip install DebugInfo

定义一个命令行参数类,

定义一个入参类,继承自 入参基类,来专门负责解析和管理我们的传入参数,示例见👇:

# -*- coding:UTF-8 -*-

# region 引入必要依赖
from DebugInfo.DebugInfo import *

# endregion

class 入参类(入参基类):
    def __init__(self):
        # 初始化基类
        super().__init__(接口说明='这个脚本是用来演示如何使用【入参基类】来管理传入参数的')


if __name__ == '__main__':
    # 打印一下 入参基类 的说明文档
    print(入参基类.__doc__)

👆上面的代码初步建立了入参类,继承自入参基类,我们通过打印入参基类doc 信息,可以查阅到相关的使用说明,如👇
DebugInfo 入参基类 __doc__信息
如👆,我们通过 doc 的说明信息得知,这个入参基类其实是在 argparse 的基础上做了二次封装,然后提供了一些易用的接口。🤭

👇下面的代码为入参类添加了我们需要接收的参数,并实例化了入参类,并解析了命令行参数:

# -*- coding:UTF-8 -*-

# region 引入必要依赖
from DebugInfo.DebugInfo import *

# endregion

class 入参类(入参基类):
    def __init__(self):
        # 初始化基类
        super().__init__(接口说明='这个脚本是用来演示如何使用【入参基类】来管理传入参数的')

        # 添加需要接收的参数
        self._添加参数('a', int, '这是 a 参数, 请输入一个数字', 0)
        self._添加参数('b', int, '这是 b 参数, 请输入一个数字', 0)
        self._添加参数('运算', ['和', '差'], '请输入运算形式', '和')


if __name__ == '__main__':
    # 实例化入参类
    入参 = 入参类()

    # 解析命令行参数
    入参.解析入参()

    # 打印获取到的参数
    print(入参.get('a'))
    print(入参.get('b'))
    print(入参.get('运算'))

👆上面的代码运行效果如👇:
DebugInfo 入参基类 解析命令行参数效果
当我们在命令行中使用 -h 参数时,还会有相应的参数帮助提示,如👇
DebugInfo 入参基类 命令行参数提示
当我们输入的参数不正确时,还有相应的错误提示,如👇
DebugInfo 入参基类 命令行参数错误提示
这么多功能,相对于我们输入的代码量来说,是不是物超所值?优雅至极?

百尺杆头,更进一步

上面的代码中,我们通过 入参.get(‘a’) 这样的方式获取了参数 a 的值.这不够优雅.
如👇的代码中,我们通过在 入参类 中定义property的方法,将每一个参数成员定义对应的getter接口,这样就可以通过 入参.a 这种方式获取和使用参数值了.同时也获得了 IDE 的成员提示和代码补全支持.

# -*- coding:UTF-8 -*-

# region 引入必要依赖
from DebugInfo.DebugInfo import *

# endregion

class 入参类(入参基类):
    def __init__(self):
        # 初始化基类
        super().__init__(接口说明='这个脚本是用来演示如何使用【入参基类】来管理传入参数的')

        # 添加需要接收的参数
        self._添加参数('a', int, '这是 a 参数, 请输入一个数字', 0)
        self._添加参数('b', int, '这是 b 参数, 请输入一个数字', 0)
        self._添加参数('运算', ['和', '差'], '请输入运算形式', '和')

    # region 访问器
    @property
    def a(self) -> int:
        if 'a' in self._参数字典:
            return self._参数字典['a'].else:
            return 0

    @a.setter
    def a(self,: int):
        if 'a' in self._参数字典:
            if type() in [int, float]:
                self._参数字典['a'].= int()

    @property
    def b(self) -> int:
        if 'b' in self._参数字典:
            return self._参数字典['b'].else:
            return 0

    @b.setter
    def b(self,: int):
        if 'b' in self._参数字典:
            if type() in [int, float]:
                self._参数字典['b'].= int()

    @property
    def 运算(self) -> str:
        if '运算' in self._参数字典:
            return self._参数字典['运算'].else:
            return ''

    @运算.setter
    def 运算(self,: str):
        if '运算' in self._参数字典:
            self._参数字典['运算'].= str()
    # endregion


if __name__ == '__main__':
    # 实例化入参类
    入参 = 入参类()

    # 解析命令行参数
    入参.解析入参()

    # 打印获取到的参数
    print(入参.a)
    print(入参.b)
    print(入参.运算)

如此优雅的命令行参数解析和管理方式,我相信你从来没有见过,独此一份了.

效率支持

上面的代码中,我们看到我们为每一个参数写一个 property 的接口,好麻烦啊.优雅个毛线.
no!no!no! 你能想到的需求,作者当然要支持上了.

👇下面的代码中, 我们通过 入参.转换为属性范式() 将每一个命令行参数自动生成其对应的访问器接口,并且自动送到您的粘贴板里,您唯一需要做的就是 ctrl-V, 惊不惊喜? 意不意外?

# -*- coding:UTF-8 -*-

# region 引入必要依赖
from DebugInfo.DebugInfo import *

# endregion

class 入参类(入参基类):
    def __init__(self):
        # 初始化基类
        super().__init__(接口说明='这个脚本是用来演示如何使用【入参基类】来管理传入参数的')

        # 添加需要接收的参数
        self._添加参数('a', int, '这是 a 参数, 请输入一个数字', 0)
        self._添加参数('b', int, '这是 b 参数, 请输入一个数字', 0)
        self._添加参数('运算', ['和', '差'], '请输入运算形式', '和')


if __name__ == '__main__':
    # 实例化入参类
    入参 = 入参类()

    # 对每一个命令行参数,生成其对应的 访问器接口
    入参.转换为属性范式()

👆上面的代码中, 入参.转换为属性范式() 的效果如👇:
DebugInfo 入参基类 命令行参数访问器接口自动生成效果
共生成了32行代码,每个参数的setter, getter属性都给你准备好了, ctrl+V 是您唯一需要做的事情了.
不让告诉我你不知道在哪里 ctrl+V 👈

如果你不希望命令行参数被setter, 你可以通过函数参数控制生成,如👇

if __name__ == '__main__':
    # 实例化入参类
    入参 = 入参类()

    # 对每一个命令行参数,生成其对应的 访问器接口
    入参.转换为属性范式(setter=False)

小结

以上所分享的命令行参数解析+管理的方式,提供自 DebugInfo 模块内的 入参基类, 虽然是基于 argparse 的一个二次封装,但相对于直接使用 argparse, 确实方便和清晰不少.

更多推荐

Android SurfaceFlinger导读(02)MessageQueue

该系列文章总纲链接:AndroidGUI系统之SurfaceFlinger系列文章目录说明:关于导读:导读部分主要是方便初学者理解SurfaceFlinger代码中的机制,为后面分析代码打下一个更好的基础,这样就可以把更多的精力放在surfaceFlinger的业务逻辑分析上。关于代码分支:以下代码分析均在androi

单元测试框架-pytest

单元测试框架-pytest官网常用插件pytest-html:生成html报告pytest-xdist:实现并发测试pytest-ordering:实现测试用例顺序设置pytest-rerunfailures:测试用例失败重试allure-pytest:生成测试报告引入依赖在项目根目录下创建:requirements.

RK3568开发笔记(七):在宿主机ubuntu上搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/132733901红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

Docker和debezium是什么关系,如何部署?

目录一、什么是Docker二、什么是debezium一、什么是DockerDocker是一种开源的容器化平台,用于构建、部署和运行应用程序。它通过将应用程序及其依赖项打包到一个称为容器的独立单元中,使应用程序能够在不同的环境中以一致的方式运行。以下是Docker的一些核心概念和特性:容器:Docker使用容器来封装应用

RK3568开发笔记(十):开发板buildroot固件移植开发的应用Demo,启动全屏显示

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/133021990红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

AI实战营第二期 第六节 《MMDetection代码课》——笔记7

文章目录什么是MMDetection?环境检测和安装1数据集准备和可视化2自定义配置文件3训练前可视化验证4模型训练5模型测试和推理6可视化分析MMYOLO环境和依赖安装特征图可视化1.可视化backbone输出的3个通道2.可视化neck输出的3个通道Grad-BasedCAM可视化检测新趋势总结什么是MMDetec

开始在 Windows 上将 Python 用于脚本和自动化

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录设置开发环境安装Python安装VisualStudioCode安装MicrosoftPython扩展在VSCode中打开集成PowerShell终端安装Git(可选)用于显示文件系统目录结构的示例脚本用于修改

rust数组

一、定义数组(一)一维数组1.指定所有元素语法格式letvariable_name:[dataType;size]=[value1,value2,value3];例如letarr:[i32;4]=[10,20,30,40];2.指定初始值和长度所有元素具有相同的值语法格式letvariable_name:[dataTy

二叉树的遍历

Ⅰ、二叉树基本介绍1.1、二叉树的定义二叉树(binarytree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。1.2、特殊的二叉树1、满二叉树:如果一

【算法训练-二叉树 三】【最大深度与直径】求二叉树的最大深度、求二叉树的直径

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【求二叉树的直径】,使用【二叉树】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为:目标公司+最近一年+出现频率排序,由高到低的去牛客TOP101去找,只有两个地方都出现过才做这道题(CodeTop本身汇聚了Le

JavaWeb 学习笔记 5:JSP

JavaWeb学习笔记5:JSP简单的说,JSP就是Java+Html,JSP的出现是为了让JavaWeb应用生成动态页面更容易。1.快速开始1.1.依赖添加JSP依赖:<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifa

热文推荐