来自目录的 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 看来,您还创建了其他未在代码中显示的子解析器、calllist 等。

您还可以在创建子解析器后定义位置参数。这就是[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 参数的主要内容,如果未能解决你的问题,请参考以下文章

使用来自另一个脚本的参数启动 python 脚本,以编程方式设置 argparse 值

python学习之argparse模块的使用

python命令行参数模块argparse

Python 处理脚本的命令行参数:使用argparse

python中的argparse包——用于解析命令行参数

Python命令行参数处理之argparse模块