python基础学习-argparse模块
argparse模块
一个可执行文件或者脚本都可以接收参数
1 | ls -l /etc |
如果把这些参数传递给程序呢?
从3.2 开始Python提供了参数分析的模块 argparse
参数分类
参数分为:
位置参数,参数放在那里,就要对应一个参数位置。例如/etc就是对应一个参数位置。
选项参数,必须通过前面是-
的短选项或者 --
的长选项,然后后面的才算它的参数,当然短选项后面也可以没有参数。
上例中,/etc
对应的是位置参数,-l
是选项参数。
ls -alh src
基本解析
先来一段最简单的程序
1 | import argparse |
运行结果
1 | python test.py -h |
argparse不仅仅做了参数的定义和解析,还自动帮助生成了帮助信息。尤其是usage,可以看到现在定义的参数是否是自己想要的。
解析器的参数
参数名称 | 说明 |
---|---|
prog | 程序的名字,缺省使用sys.argv[0] |
add_help | 自动为解析器增加 -h 和 –help 选项,默认为True |
description | 为程序功能添加描述 |
parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents')
1 | $ python test.py --help |
位置参数解析
ls 基本功能应该解决目录内容的打印。
打印的时候应该指定目录路径,需要位置参数。
1 | import argparse |
程序等定义为:
ls [-h] path
-h 为帮助,可有可无
path为位置参数,必须提供
传参
parse_args(args=None,namespace=None)
args 参数列表,一个可迭代对象。内部会把可迭代对象转换成list。如果为None则使用命令行传入参数,非None则使用args参数的可迭代对象。
1 | import argparse |
Namespace(path=’/etc’)里面的path参数存储在了一个Namespace对象内的属性上,可以通过Namespace对象属性来访问,例如args.path
非必须位置参数
上面的代码必须输入位置参数,否则会报错。
1 | usage: ls [-h] path |
但有时候,ls 命令不输入任何路径的话就表示列出当前目录的文件列表。
1 | import argparse |
可以看出path也变成可选的位置参数,没有提供就使用默认值 .
点号表示当前路径。
- help 表示帮助文档中这个参数的描述
- nargs 表示这个参数接收结果参数,?表示可有可无,+表示至少一个,*可以任意个,数字表示必须是指定数目个
- default 表示如果不提供该参数,就使用这个值。一般和?、*配合,因为它们都可以不提供位置参数,不提供就是用缺省值
选项参数
-l 的实现
parser.add_argument('-l')
就增加了选项参数,参数定义为ls [-h] [-l L] [path]
和我们要的形式有一点出入,我们期望的是[-h],怎么解决?
nargs能够解决吗?
parser.add_argument('-l',nargs='?')
ls [-h] [-l [L]] [path]
L变成了可选,而不是-l
那么,直接把nargs=0,意思就是让这个选项接收0个参数,如下:
parser.add_argument('-l',nargs=0)
结果,抛出异常
为了这个问题,使用action参数
parser.add_argument('-l',action='store_true')
看到命令定义变成了 ls [-h] [-l] [path]
提供-l选项,例如:
ls -l
得到 Namespace(l=True,path='.')
ls
得到 Namespace(l=False,path='.')
这样用True、False来判断用户是否提供了该选项
-a 的实现
parser.add_argument('-a','--all',action='store_true')
长短选项可以同时给出。
代码
1 | import argparse |
ls 业务功能的实现
到目前为止,已经解决了参数的定义和传参的问题,下面就要解决业务问题:
- 列出所有指定路径的文件,默认是不递归的
- -a 显示所有文件,包括隐藏文件
- -l 详细列表模式显示
代码实现
1 | import argparse |
mode 是整数,八进制描述的权限,最终显示为rwx的格式。
方法1
1 | modelist = ['r','w','x','r','w','x','r','w','x'] |
方法2:
1 | modelist = dict(zip(range(9),['r','w','x','r','w','x','r','w','x'])) |
合并列出文件函数
listdirdetail 和listdir几乎一样,重复太多,合并
1 | import argparse |
排序
ls 的显示是把文件名按照升序排序输出
1 | # 排序 |
完整代码
再次重构代码
1 | import argparse |
-h 的实现
-h, –human-readable,如果-l 存在,-h 有效
- 增加选项参数
1 | parser = argparse.ArgumentParser(prog='ls',description='list directory contents',add_help=False) |
- 增加一个函数,能够解决单位转换的
1 | def _gethuman(size: int): |
- 在-l逻辑部分增加处理
1 | size = stat.st_size if not human else _gethuman(stat.st_size) |
其他的完善
uid、gid的转换
pwd模块,The password database ,提供访问Linux、Unix的password文件的方式。windows没有。
pwd.getpwuid(Path().stat().st_uid).pw_name
grp模块,Linux、Unix获取组信息的模块。windows没有
grp.getgrgid(Path().stat().st_gid).gr_name
pathlib模块,Path().group()或者Path().owner()也可以,本质上它们就是调用pwd模块和grp模块
由于windows不支持,这次可以不加这个uid、gid的转换
代码改进
1 | import argparse |
改进mode的方法
使用stat模块
1 | import stat |
最终代码
1 | 实现ls命令功能,实现-l、-a和--all、-h选项 |
测试
1 | $ python xxx.py -lah |
思考
如果要实现ls -lah /etc /tmp /home 怎么实现
python基础学习-argparse模块
https://python0.netlify.app/2020/01/10/python基础学习-argparse模块/