Python3 argparse set_默认值不';不能将字符串作为选项名?
我是argparse新手,所以这可能是最基本的 我更喜欢将所有字符串常量定义一次(Python3 argparse set_默认值不';不能将字符串作为选项名?,python,python-3.x,argparse,Python,Python 3.x,Argparse,我是argparse新手,所以这可能是最基本的 我更喜欢将所有字符串常量定义一次(blah='foo'),然后在整个代码中使用它。当我进入set_defaults时,我似乎仅限于kwarg类型的参数 也就是说,parser.set\u默认值(NUM=ONE)不将NUM视为字符串。下面是一个更完整的例子: ONE = 'one' TWO = 'two' SIX = 'six' NUMBER_OPTS = [ONE, TWO, SIX] NUM = 'num' parser = argparse.
blah='foo'
),然后在整个代码中使用它。当我进入set_defaults
时,我似乎仅限于kwarg类型的参数
也就是说,parser.set\u默认值(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\u参数
将字符串作为目标,而set\u默认值
则不这样做。您可以使用字典扩展:
parser.set_defaults(**{NUM: ONE})
您可以使用'sdefault
参数执行以下操作:
pform.add_argument('--'+opt, dest=NUM, action='store_const', const=opt, default=NUM)
只需稍加修改即可运行代码:
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\u参数
语句创建的3个Action
对象的指针。我本可以从pform.\u group\u actions
中获得相同的列表,因为这些操作已添加到该组中
通过显式设置dest
,它是'num'
,而不是opt
(源自长标志):
parser.set\u 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')
对于列表中的第一个,使用默认值
也就足够了,剩下的则是默认值无
。这是在解析开始时设置默认值的结果
我可以通过以下方式进行验证:
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'
(\uu
是前面的答案。它也存储在Out
列表中。)
另一个技巧是在解析之前定义名称空间对象。此处定义的任何值都优先于默认值。请注意,名称空间(…)
定义与设置默认值的语法相同:
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'
是一个字符串。在dest=NUM
中,dest
是符号,NUM
的值是字符串值。在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
和setattr
读取和设置这些属性的值:
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')
用于
In [80]: set_defaults(parser, {NUM: 'three'}) # diff value
In [81]: parser.parse_args([])
Out[81]: Namespace(num='three')
诚然,这并没有多大改变;只需消除**
扩展。Python中根本没有办法使(…NUM=ONE…)表示(…'NUM':ONE…)
也许这整本字典的生意都是在转移注意力。我们可以传递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
值与默认值配对的方法。它不必是一个字典key:value
mapping。这是一个很好的字典。我还试图找出解决这个问题的办法。。。这个解决方案非常优雅!谢谢,就这样。很遗憾,这种迂回的方法是必需的,但我的蟒蛇本能提高了一个等级。很抱歉之前的否决票。这纯粹是意外。我原以为我投了更高的票,但不知怎的注意到我有-1个代表。@quantummechanical,这个方法的签名是set\u defaults(self,**kwargs)
argparse
经常使用**kwargs
样式。例如:添加参数(self、*args、**kwargs)
。因此,请熟悉Python的用法。并在argparse.py
@hpaulj中查找这些方法的源代码:谢谢您的评论。我确实查找了源代码,但源代码没有告诉我@Daniel对**{NUM:ONE}
的解决方案。事实上,这是一个微妙而晦涩的语法,因为它没有一个明显的名称,你必须已经知道它来猜测它。我也记不起另一种语言,在这种语言中,字符串变量必须经过双重解释才能正确传递给方法。(这里是:(1)在匿名dict中用作dict键,(2)在方法调用中解压dict。)是的,这适用于一般情况。对于我的特定示例,我正在遍历一个选项名列表,所有选项名都具有相同的目标。我假设最后处理的选项名称是默认名称。(对于dict键而不是列表,不需要任何顺序,如果不强制执行顺序,我就无法提前知道保留了哪个默认值。)@QuantumMechanic,set_defaults
按照定义的顺序迭代操作(参数),并(重新)将其dest
的default
设置为新值parse_args
使用相同的操作列表在解析开始时设置默认值。对于重复的dest
,将使用第一个。您的NUM
也不能作为属性名,如ar
In [80]: set_defaults(parser, {NUM: 'three'}) # diff value
In [81]: parser.parse_args([])
Out[81]: Namespace(num='three')
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')