【问题标题】:Python argparse: how to reference a parameter with a dash in itPython argparse:如何引用带有破折号的参数
【发布时间】:2020-11-25 01:23:01
【问题描述】:

我正在使用argparse,我想指定位置参数,其中包含一个破折号。 argparse 似乎让我这样做。事实上,它出现在 parse_args() 的命名空间中,但我不知道如何引用相应的值。这是一个最小的例子(注意'a-string'中的破折号):

#!/usr/bin/env python3

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('a-string', help='A string')

args = parser.parse_args()

# AttributeError: 'Namespace' object has no attribute 'a_string'
#print("Argument was: " + args.a_string)

# TypeError: 'Namespace' object is not subscriptable
#print("Argument was: " + args['a-string'])

# AttributeError: 'Namespace' object has no attribute 'a'
#print("Argument was: " + args.a-string)

# I give up. Ask StackOverflow.

我最初想用add_argumentdest 参数来解决这个问题,但是如果我将dest 添加到位置参数,我会得到“ValueError:dest 为位置参数提供了两次”。如何引用此位置参数的值?

【问题讨论】:

    标签: python argparse


    【解决方案1】:

    参数作为parse_args() 返回的命名空间对象的属性给出。但是标识符(包括属性)中不能有连字符(如果您想直接访问它们,至少不能),因为它是一个减号,这意味着别的东西。

    如果您希望将您的参数命名为“a-string”给用户,但可以在您的代码中以a_string 访问(这是您尝试的方法之一),您可以使用metavar 参数来指定它的描述方式给用户。

    parser.add_argument('a_string', help='A string', metavar='a-string')
    
    args = parser.parse_args()
    print(args.a_string)
    

    参数将在使用信息中显示为:

    positional arguments:
      a-string    A string
    

    https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument

    【讨论】:

    • 'dest' 不适用于位置参数。注意我的最后一段。
    • 所以你做到了。然后换一种方式:将a_string 设为其实际名称,并使用metavar 更改其向用户显示的方式。
    • 啊,创意。我没有想过颠倒我的想法并使用metavar。老实说,我希望 argparse 将 'dest' 作为位置参数的一个选项。这将最自然地解决我的问题。但是您的 metavar 想法有效,所以我会使用它。谢谢。
    • 是的,我很惊讶dest 不起作用。但它确实对关键字参数更有意义,其中变量名实际上是用户命令的一部分。
    • 对于一个位置,第一个参数是dest;这就是为什么您不能再次为其提供关键字。
    【解决方案2】:

    dest 带有“-”的处理方式与可选和位置不同。

    In [298]: import argparse                                                                            
    In [299]: parser = argparse.ArgumentParser()                                                         
    In [300]: a1 = parser.add_argument('--a-string');                                                 
    In [301]: a2 = parser.add_argument('foo-string');                                                    
    In [302]: parser.print_help()                                                                        
    usage: ipython3 [-h] [--a-string A_STRING] foo-string
    
    positional arguments:
      foo-string
    
    optional arguments:
      -h, --help           show this help message and exit
      --a-string A_STRING
    

    optionaldest 派生自第一个“long”标志,将任何内部“-”替换为“_”。位置的dest 是第一个参数,没有任何替换。您可以完全控制位置dest

    In [304]: args = parser.parse_args(['xxx'])                                                          
    In [305]: args                                                                                       
    Out[305]: Namespace(a_string=None, **{'foo-string': 'xxx'})
    In [306]: args.a_string                                                                              
    

    dash dest 仍然可以访问:

    In [307]: vars(args)['foo-string']                                                                   
    Out[307]: 'xxx'
    In [308]: getattr(args, 'foo-string')                                                                
    Out[308]: 'xxx'
    

    “-/_”替换已完成,因此您可以在标志中使用“-”(常见的 POSIX 实践),但仍使用点语法访问属性。

    在内部argparse 使用getattrsetattr,因此它不限制dest。它不必是有效的 python 名称。这适用于可选项和位置。

    如果我给可选的 dest 值(与标志不同),

    In [310]: a1.dest = 'a-string'     # changing the existing argument
                                                                  
    In [312]: parser.print_help()                                                                        
    usage: ipython3 [-h] [--a-string A-STRING] foo-string
    
    positional arguments:
      foo-string
    
    optional arguments:
      -h, --help           show this help message and exit
      --a-string A-STRING
    

    这将“A_STRING”更改为“A-STRING”,但也更改了属性名称:

    In [313]: args = parser.parse_args(['xxx'])                                                          
    In [314]: args                                                                                       
    Out[314]: Namespace(**{'a-string': None, 'foo-string': 'xxx'})
    

    metavar 让我们控制值在帮助中的显示方式。然后我们可以选择dest 来做任何实用的东西(或者如果我们愿意,也可以选择不实用的东西)。

    In [315]: a1.dest='a_string'; a1.metavar='MY-STRING'                                                 
    In [316]: a2.dest='foo_bar'; a2.metavar='YOUR-STRING'                                                
    In [317]: parser.print_help()                                                                        
    usage: ipython3 [-h] [--a-string MY-STRING] YOUR-STRING
    
    positional arguments:
      YOUR-STRING
    
    optional arguments:
      -h, --help            show this help message and exit
      --a-string MY-STRING
    In [318]: args = parser.parse_args(['xxx'])                                                          
    In [319]: args                                                                                       
    Out[319]: Namespace(a_string=None, foo_bar='xxx')
    

    丑陋的dest,独立于flags和metavar:

    In [320]: a1.dest='a-#$'; a2.dest='-xxx$3'                                                           
    In [321]: args = parser.parse_args(['xxx'])                                                          
    In [322]: args                                                                                       
    Out[322]: Namespace(**{'-xxx$3': 'xxx', 'a-#$': None})
    In [323]: getattr(args, '-xxx$3')                                                                    
    Out[323]: 'xxx'
    In [324]: parser.print_usage()                                                                       
    usage: ipython3 [-h] [--a-string MY-STRING] YOUR-STRING
    

    有些人认为位置应该执行 '-/_' 替换。但是由于metavar 可以完全控制帮助显示,因此没有必要这样做。充其量只是让positionals 表现得更像'可选'。

    metavar 的选项更加有限。特殊字符可能会弄乱usage 格式,尤其是在使用很长(多行)或具有互斥组的情况下。这种格式相当脆弱。

    【讨论】:

      猜你喜欢
      • 2012-07-03
      • 2019-03-09
      • 2021-05-06
      • 2012-10-21
      • 2018-04-22
      • 2013-04-17
      相关资源
      最近更新 更多