当前位置: 首页 > 后端技术 > Python

Python命令行之旅:深入argparse(二)

时间:2023-03-25 20:58:38 Python

作者:HelloGitHub-Prodesire前言在上一篇《深入argparse(一)》中,我们深入了解了argparse,包括参数动作和参数类别。基本功能,能够编写简单的命令行程序。本文将继续深入了解argparse的高级玩法,一窥其全貌,帮助我们具备实现复杂命令行程序的能力。本系列文章默认使用Python3作为解释器。如果你还在使用Python2,请注意两者在语法和库使用上的区别~Help自动生成帮助当你在命令行程序中指定-h或--help参数时,会输出帮助信息。而argparse可以通过指定add_help入参为True或不指定来达到自动输出帮助信息的目的。>>>导入argparse>>>解析器=argparse。ArgumentParser(add_help=True)>>>解析器。add_argument('--foo')>>>解析器。parse_args(['-h'])用法:[-h][--fooFOO]可选参数:-h,--help显示此帮助信息并退出--fooFOO如果add_help=False,则指定-hon命令行会报错:>>>importargparse>>>parser=argparse.ArgumentParser(add_help=False)>>>parser.add_argument('--foo')>>>parser.parse_args(['-h'])usage:[--fooFOO]:error:unrecognizedarguments:-hcustomhelpArgumentParser使用formatter_class输入参数来控制输出帮助格式。例如,通过指定formatter_class=argparse.RawTextHelpFormatter,我们可以使帮助内容遵循原始格式:>>>importargparse>>>parser=argparse.ArgumentParser(...add_help=True,...formatter_class=argparse.RawTextHelpFormatter,...description="""...description...raw...formatted"""...)>>>解析器。add_argument(...'-a',action="store_true",...help="""argument...raw...格式化..."""...)>>>>>>解析器.parse_args(['-h'])usage:[-h][-a]descriptionrawformattedoptionalarguments:-h,--helpshowthishelpmessageandexit-aargumentrawformatted在不指定formatter_class的情况下比较帮助输出,你可以找到descirption和-a帮助内容的区别:>>>importargparse>>>parser=argparse。ArgumentParser(...add_help=True,...description="""...description...notraw...格式化"""...)>>>解析器。add_argument(...'-a',action="store_true",...help="""argument...notraw...格式化..."""..)>>>parser.parse_args(['-h'])usage:[-h][-a]descriptionnotrawformattedoptionalarguments:-h,--help显示帮助信息并退出-aargumentnotrawformattedparametergroup有时,我们需要对参数进行分组显示帮助信息时可以一起显示。例如,命令行支持三个参数选项--user、--password和--push。前两个需要放在一个名为authentication的文件中,表明是身份认证信息。然后我们可以使用ArgumentParser.add_argument_group来满足:>>>importargparse>>>parser=argparse.ArgumentParser()>>>group=parser.add_argument_group('authentication')>>>group.add_argument('--user',action="store")>>>group.add_argument('--password',action="store")>>>parser.add_argument('--push',action='store')>>>解析器。parse_args(['-h'])用法:[-h][--userUSER][--passwordPASSWORD][--pushPUSH]可选参数:-h,--help显示此帮助信息并退出--pushPUSAuthentication:--userUSER--passwordPASSWORD可以看到我们在输出帮助信息的时候,认证组中同时出现了--user和--password选项。选项参数前缀不知道大家有没有注意到,命令行程序的选项参数前缀在不同的平台上可能是不一样的。比如在Unix上,它的前缀是-;在Windows上,大多数命令行程序(例如findstr)选项参数都以/为前缀。在argparse中,选项参数前缀默认为Unix命令行约定,即-。但它也支持自定义前缀,这里是一个例子:>>>importargparse>>>>>>parser=argparse.ArgumentParser(...description='Optionprefix',...prefix_chars='-+/',...)>>>>>>parser.add_argument('-power',action="store_false",...default=None,...help='Setpoweroff',...)>>>parser.add_argument('+power',action="store_true",...default=None,...help='Setpoweron',...)>>>parser.add_argument('/win',...action="store_true",...default=False)>>>parser.parse_args(['-power'])Namespace(power=False,win=False)>>>parser.parse_args(['+power','/win'])Namespace(power=True,win=True)在这个例子中,我们指定了三个选项参数前缀-、+和/,因此:通过指定选项参数-power,使power=FalseBy指定选项参数+power,makepower=True通过指定选项参数/win,makewin=True共享解析器有时候我们需要共享解析器来共享里面的参数配置。比如我们的命令行工具需要支持在阿里云和AWS上的操作。两种操作都需要指定AccessKeyId和AccessKeySecret来表示用户身份和权限。那么就特别有必要共享解析器,这样可以减少代码的重复。我们可以通过在base.py中定义一个父解析器来将AccessKey相关的参数配置存储为一个公共解析器。由于后续的子解析器会自动生成帮助信息,这里父解析器指定add_help=False不自动生成帮助信息:#bash.pyimportargparseparser=argparse.ArgumentParser(add_help=False)parser.add_argument('--ak-id',action="store")parser.add_argument('--ak-secret',action="store")然后就可以分别在ali.py和aws.py中定义子解析器,通过parents进入参考上述父解析器继承公共参数并实现自己的参数:#ali.pyimportargparseimportbaseparser=argparse.ArgumentParser(parents=[base.parser],)parser.add_argument('--ros',action="store_true",default=False,help='使用ROS服务编排云资源')print(parser.parse_args())#aws.pyimportargparseimportbaseparser=argparse.ArgumentParser(parents=[base.parser],)parser.add_argument('--cloudformation',action="store_true",default=False,help='使用CloudFormation服务来orchestratecloudresources')print(parser.parse_args())最后传入-h参数可以看到ali.py和aws.py支持的参数,常用参数对于--ak-id和--ak-secret,具体参数分别是--ros和--cloudformation:$python3ali.py-husage:ali.py[-h][--ak-idAK_ID][--ak-secretAK_SECRET][--ros]可选参数:-h,--help显示此帮助消息并退出--ak-idAK_ID--ak-secretAK_SECRET--ros使用ROS服务编排云资源$python3aws.py-husage:aws.py[-h][--ak-idAK_ID][--ak-secretAK_SECRET][--cloudformation]可选参数:-h,--help显示此帮助消息并退出--ak-idAK_ID--ak-secretAK_SECRET--cloudformation使用CloudFormation服务编排云资源嵌套解析器在我们前面介绍的命令行中,使用形式通常是cli--a--bxxx,但是还有一个非常常用的命令行使用方式是clisubcmd--a--bxxx。例如,当我们想通过git推送标签时,我们会使用gitpush--tags。通过实现嵌套解析器,我们可以很容易地解析这个子命令形式。在嵌套解析器中,我们定义一个父解析器作为整个命令行的入口,然后定义N个子解析器对应N个子命令,从而实现整个功能。在下面的例子中,我们支持两个子命令create和delete来创建或删除指定的路径。delete命令支持--recursive参数表示是否递归删除指定路径:#cli.pyimportargparseparser=argparse.ArgumentParser()subparsers=parser.add_subparsers(help='commands')#createcreate_parser=subparsers.add_parser('create',help='创建一个目录')create_parser.add_argument('dirname',action='store',help='要创建的新目录')#deletelete_parser=subparsers.add_parser('delete',help='删除一个目录directory')delete_parser.add_argument('dirname',action='store',help='Thedirectorytoremove')delete_parser.add_argument('--recursive','-r',default=False,action='store_true',help='递归删除目录',)print(parser.parse_args())直接指定-h查看支持的子命令和参数选项:$python3cli.py-husage:cli.py[-h]{create,delete}...位置参数:{create,delete}命令create创建目录delete删除目录可选参数:-h,--helpshowthishelpmessage和exit直接指定delete-h查看deletesub命令支持的参数选项:$python3cli.pydelete-husage:cli.pydelete[-h][--recursive]dirnamepositionalarguments:dirnameThedirectorytoremoveoptionalarguments:-h,--helpshowthishelpmessageandexit--recursive,-r递归移除目录自定义action在上一篇《深入argparse(一)》中介绍了8种参数action,可以说涵盖了大部分场景但也有一些特定的requirements无法满足,比如要求的参数值全部大写。这是自定义操作派上用场的地方。实现一个自定义action类,需要继承自argparse.Action,并将这个自定义action类传入ArgumentParser.add_argument的action参数中。解析器在解析参数的时候,会调用这个类的__call__方法。该方法的签名为__call__(self,parser,namespace,values,option_string=None),其中:parser存储解析器实例命名空间的解析结果值,即命令行传入的参数值option_string为参数选项。在下面的例子中,我们通过--words传入words,在自定义action类中将其值转为大写:#cli.pyimportargparseclassWordsAction(argparse.Action):def__call__(self,parser,namespace,values,option_string=None):print(f'parser={parser}')print(f'values={values!r}')print(f'option_string={option_string!r}')values=[v.upper()forvinvalues]setattr(namespace,self.dest,values)parser=argparse.ArgumentParser()parser.add_argument('--words',nargs='*',action=WordsAction)results=parser.parse_args()print(results)$python3cli.py--wordsfoobarparser=ArgumentParser(prog='cli.py',usage=None,description=None,formatter_class=,conflict_handler='错误',add_help=True)values=['foo','bar']option_string='--words'Namespac在e(words=['FOO','BAR'])部分,通过由浅入深对argparse的介绍,相信你已经充分领略了argparse的强大,具备了开发命令行工具的能力。感觉肤浅,绝对知道此事必须修炼。下一篇文章将带大家使用argparse实现日常工作中常用的git命令。想想看,是不是有点小激动?欢迎关注HelloGitHub公众号获取更多开源项目的资讯和内容。《解释开源项目系列》上线——让对开源项目感兴趣的人不再害怕,让开源项目的发起者不再孤单。关注我们的文章,您将发现编程的乐趣,使用并发现参与开源项目是多么容易。欢迎联系我们投稿,让更多的人爱上开源,为开源做贡献~