Python3 argparse set\u defaults不接受字符串作为选项名?

2024-04-25 19:39:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我是argparse新手,所以这可能是基础。在

我希望所有的字符串常量都定义一次(blah = 'foo'),然后在整个代码中使用它。当我到达set_defaults时,似乎我仅限于kwarg类型的参数。在

也就是说,parser.set_defaults(NUM=ONE)不将NUM视为字符串。这里有一个更完整的例子:

ONE = 'one'
TWO = 'two'
SIX = 'six'
NUMBER_OPTS = [ONE, TWO, SIX]
NUM = 'num'

parser = argparse.ArgumentParser()
pform = parser.add_mutually_exclusive_group()
for opt in NUMBER_OPTS:
    pform.add_argument('--'+opt, dest=NUM, action='store_const', const=opt)
parser.set_defaults(NUM=ONE) # Can't find a syntax to make this DWIM
args = parser.parse_args()
print("%s is %s" % (NUM, vars(args)[NUM]))

所以当add_argument接受一个字符串作为目的地时,set_defaults则不是


Tags: 字符串addparsernumberargparseargsonenum
3条回答

您可以使用字典扩展:

parser.set_defaults(**{NUM: ONE})

只需稍作修改即可运行代码:

In [35]: ONE = 'one'
    ...: TWO = 'two'
    ...: SIX = 'six'
    ...: NUMBER_OPTS = [ONE, TWO, SIX]
    ...: NUM = 'num'
    ...: alist = []
    ...: parser = argparse.ArgumentParser()
    ...: pform = parser.add_mutually_exclusive_group()
    ...: for opt in NUMBER_OPTS:
    ...:     a = pform.add_argument(' '+opt, dest=NUM, action='store_const', co
    ...: nst=opt)
    ...:     alist.append(a)

In [37]: alist
Out[37]: 
[_StoreConstAction(option_strings=[' one'], dest='num', nargs=0, const='one', default=None, type=None, choices=None, help=None, metavar=None),
 _StoreConstAction(option_strings=[' two'], dest='num', nargs=0, const='two', default=None, type=None, choices=None, help=None, metavar=None),
 _StoreConstAction(option_strings=[' six'], dest='num', nargs=0, const='six', default=None, type=None, choices=None, help=None, metavar=None)]

alist包含指向由add_argument语句创建的3Action对象的指针。我本来可以从pform._group_actions得到相同的列表,因为这些动作被添加到了那个组中。在

通过显式设置dest,它是'num',而不是{}(从long标志派生):

^{pr2}$

parser.set_defaults(num=ONE)将带有dest='one'的操作的default属性设置为“one”。在

In [45]: [a.default for a in alist]
Out[45]: ['one', 'one', 'one']
In [46]: [a.const for a in alist]
Out[46]: ['one', 'two', 'six']

此默认值也可以在循环中定义为:

pform.add_argument(' '+opt, dest=NUM, default=ONE, const=opt, , action='store_const')

对于列表中的第一个,default也足够了,剩下的是默认的None。这是解析开始时如何设置默认值的结果。在

我可以用以下方法验证:

In [47]: alist[1].default=TWO
In [48]: alist[2].default=SIX
In [49]: parser.parse_args([])
Out[49]: Namespace(num='one')

const按预期工作:

In [50]: parser.parse_args([' two'])
Out[50]: Namespace(num='two')

解析的命名空间中的num值可以通过多种方式获取:

In [51]: _.num                   # as attribute
Out[51]: 'two'
In [52]: getattr(Out[50],'num')   # NUM works here
Out[52]: 'two'
In [53]: vars(Out[50])['num']     # dictionary, NUM works here
Out[53]: 'two'

_是前面的答案。它也存储在Out列表中。)

另一个技巧是在解析之前定义一个命名空间对象。在那里定义的任何值优先于默认值。请注意,Namespace(...)定义与set_defaults具有相同的语法:

In [54]: ns = argparse.Namespace(num='four')
In [55]: parser.parse_args([], namespace=ns)
Out[55]: Namespace(num='four')
In [56]: parser.parse_args([' six'], namespace=ns)
Out[56]: Namespace(num='six')

与大多数语言一样,Python对符号和字符串进行了区分。只引用字符串。符号可用于命名变量、对象属性和函数关键字。在

在您的例子中,NUM是一个符号,'num'是一个字符串。{{{cd21>中的值是{cd21}的值。在alist[0].dest中,dest是属性名,其值是字符串'num'。在

但是argparse接受这个a.dest值,并使用它在args命名空间中定义一个属性。这就是为什么num可以用作下面的属性名:

In [58]: args = parser.parse_args([' six'])
In [59]: args
Out[59]: Namespace(num='six')
In [60]: args.num
Out[60]: 'six'

argparse实际上使用getattr和{}读取并设置这些属性的值:

In [61]: getattr(args, 'num')
Out[61]: 'six'
In [62]: getattr(args, alist[0].dest)
Out[62]: 'six'

这对dest值施加了一些假设;它们甚至不必是有效的属性名。在

我在一篇评论中指出,字典也可以用符号和字符串来定义:

In [63]: {'num':'one'}
Out[63]: {'num': 'one'}
In [64]: dict(num='one')
Out[64]: {'num': 'one'}

关键字参数,包括开放的**kwargs,也跨越了符号/字符串边界:

In [65]: def foo(**kwargs):
    ...:     print(kwargs)
    ...:     
In [66]: foo(num='one')    # keyword input
{'num': 'one'}
In [67]: foo(**Out[63])    # expand a dictionary
{'num': 'one'}

因此,虽然Python区分了符号和字符串,但它有各种跨越边界的方式。在


NUM=ONE运行,但定义了一个args.NUM属性。在

In [72]: parser.set_defaults(NUM=ONE)
In [73]: parser.parse_args([])
Out[73]: Namespace(NUM='one', num='one')
In [74]: parser.parse_args([]).NUM
Out[74]: 'one'

现在让我们去掉NUM默认值

In [76]: parser._defaults
Out[76]: {'NUM': 'one', 'num': 'one'}
In [78]: del parser._defaults['NUM']
In [79]: parser.parse_args([])
Out[79]: Namespace(num='one')

def set_defaults(self, **kwargs):
    # original method, takes keyword-value or **dict
    self._defaults.update(kwargs)

    # if these defaults match any existing arguments, replace
    # the previous default on the object with the new one
    for action in self._actions:
        if action.dest in kwargs:
            action.default = kwargs[action.dest]

def set_defaults(parser, adict):
    # function version that takes a dictionary rather than **kwargs
    parser._defaults.update(adict)
    for action in parser._actions:
        if action.dest in adict:
            action.default = adict[action.dest]

用于

In [80]: set_defaults(parser, {NUM: 'three'})  # diff value
In [81]: parser.parse_args([])
Out[81]: Namespace(num='three')

诚然,这并没有太大变化;只是消除了**扩展。在Python中没有办法使(…NUM=ONE…)表示(…'num':一个。在

也许这整本字典的生意都是在偷懒。我们可以传递dest和default的元组

def set_defaults(parser, alist):
    # function version that takes a list of tuples
    for dest, default in alist: # iterate on tuples
        for action in parser._actions:
            if action.dest == dest:
                action.default = default

In [83]: set_defaults(parser, [(NUM, SIX)])
In [84]: parser.parse_args([])
Out[84]: Namespace(num='six')

换句话说,我们只需要一种将dest值与default值配对的方法。它不一定是一个字典key:value映射。在

您可以使用^{}default参数来执行此操作:

pform.add_argument(' '+opt, dest=NUM, action='store_const', const=opt, default=NUM)

相关问题 更多 >