来自目录的 argparse python 参数
Posted
技术标签:
【中文标题】来自目录的 argparse python 参数【英文标题】:arparse python argument from directory 【发布时间】:2015-11-25 17:51:06 【问题描述】:我有这样的文件结构:
project/
main_prog.py
tools/
script.py
md_script/
__init__.py
md_script.py
我在工具中搜索本地 python 模块。在本例中,它是 md_script。我想在我的代码中使用它作为位置参数,比如安装,但是当我使用它时,我得到了一个错误:
./jsh.py md_script
usage: jsh.py [-h] install,call,list,log,restore ... [md_script]
jsh.py: error: invalid choice: 'md_script' (choose from 'install', 'call', 'list', 'log', 'restore')
ubuntu14.10 上的 python3.4 这是我的代码:
parser = argparse.ArgumentParser(prog='jsh.py',
description='Some help.', epilog='Example of usage: some help')
subparsers = parser.add_subparsers()
parser_install = subparsers.add_parser('install', help = 'Install new project.')
parser_install.add_argument('install', nargs='?', help = 'Name of project to be installed')
if os.path.isdir(full/path/to/tools/):
name_arg = next(os.walk(full/path/to/tools))[1]
tools_arg = parser.add_argument_group('Tools', 'Modules from tools')
for element in name_arg:
tools_arg.add_argument(element, nargs='?', help='md_script description')
args = parser.parse_args()
try:
if not len(sys.argv) > 1:
parser.print_help()
elif 'install' in args:
do_some_stuff
elif element in args:
do_some_md_script_stuff
else:
parser.print_help()
【问题讨论】:
【参考方案1】:usage
行显示出了什么问题:
usage: jsh.py [-h] install,call,list,log,restore ... [md_script]
你需要使用类似的东西
jsh.py install md_script
你指定了子解析器,所以你必须给它一个子解析器的名字。
从usage
看来,您还创建了其他未在代码中显示的子解析器、call
、list
等。
您还可以在创建子解析器后定义位置参数。这就是[md_script]
的来源。小心制作大量nargs='?'
位置(包括install
子解析器的参数)。这可能会使您的用户感到困惑。事实上,它似乎让你感到困惑。请记住,subparser
实际上是一个位置参数(需要 1 个字符串)。
我建议在创建这么复杂的解析器之前尝试使用更简单的解析器。
所以从您的 cmets 和示例中,我看到您的目标是让用户命名一个模块,以便您的脚本可以以某种方式调用它。因为使用这些名称填充子解析器是有意义的。
我想知道您为什么还要创建一个具有相同名称的可选位置参数:
module_pars = subparsers.add_parser(element, help = 'Modules from tools')
module_pars.add_argument(element, nargs='?', help=element+' description')
那是因为您使用属性的存在作为该子解析器被调用的证据吗?
elif element in args:
do_some_md_script_stuff
argparse
文档还有其他一些想法。
处理子命令的一种特别有效的方法是将 add_subparsers() 方法的使用与对 set_defaults() 的调用结合起来,以便每个子解析器知道它应该执行哪个 Python 函数。
和
但是,如果需要检查被调用的子解析器的名称,add_subparsers() 调用的 dest 关键字参数将起作用:
这些避免了“?”的混乱位置参数,让您可以使用子解析器参数获取真实信息。
subparsers = parser.add_subparsers(dest='module')
....
for element in name_arg:
# module_pars = 'parser_'+element # this does nothing
module_pars = subparsers.add_parser(element, help = 'Modules from tools')
module_pars.set_defaults(func = do_some_md_script_stuff)
# or module_pars.set_default(element='I am here')
module_pars.add_argument('real_argument')
现在你可以检查了:
if args.module='md_script':
do_some_md_script_stuff(args)
或
if hasattr(args, 'func'):
func(args)
使用替代 set_defaults
,您的原始测试应该仍然有效:
if element in args:
do_some_md_script_stuff
【讨论】:
所以我不应该使用组解析器,而是使用下一个子解析器?对于目录中的每个模块,我应该创建新的子解析器吗?但是如何动态创建呢? 而且,是的,代码大约有 350 行,在 5 个子解析器中有 6 个参数。我需要将它实现为位置参数。这对所有人都很好。只有“模块解析器”会返回错误。我知道这种用法告诉我,使用 install... 之一来使用 md_script,但我需要像 ./mainprog.py md_script 一样运行它。我尝试创建另一个子解析器,但失败了。 我不明白像“安装”这样的子解析器和这个目录结构之间的关系。我建议制作除子解析器之外的所有参数optionals
(带有--
标志)。这使您可以更好地控制他们的顺序和身份。
这不取决于我。我想这样做是可选的。快捷方便。但这是主要思想,使所有论点都具有位置性。这样做很容易: ./jsh.py call md_script 但这仍然不是必需的方法。这不是一个位置。有什么办法吗?
Tools 只是一个普通目录,其中我有脚本可以使用的所有工具,例如其他脚本(由 ./jsh.py 调用 script.py 使用)和本地模块(应该使用像 ./jsh.py md_script) 这样使用模块是一个问题。我不知道如何实现创建动态子解析器。或者也许还有另一种方式?【参考方案2】:
我是这样做的。这正是我想要的。
if os.path.isdir(TOOLS_PATH):
name_arg = next(os.walk(TOOLS_PATH))[1]
for element in name_arg:
module_pars = 'parser_'+element
module_pars = subparsers.add_parser(element, help = 'Modules from tools')
module_pars.add_argument(element, nargs='?', help=element+' description')
我没有测试它,因为我没有测试模块,但./jsh.py md_script
进入elif element in args: print('md_script')
并打印字符串。所以看起来它有效。
感谢所有回复。
编辑:我测试了它。在 add_argument 我必须改变 nargs='?'用于 nargs='*' 捕获多个参数。 为了从命令行捕获参数,我使用了这个:
elif args:
for element in name_arg:
if element in args:
element_arg = sys.argv[2:]
done_cmd,msg = opt_exec_module(element,*element_arg)
my_logger(done_cmd,msg)
不是很优雅,但它确实有效。
【讨论】:
我添加了一个关于“?”的注释我的回答中的位置命名为“元素”。以上是关于来自目录的 argparse python 参数的主要内容,如果未能解决你的问题,请参考以下文章