Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python3 argparse set_默认值不';不能将字符串作为选项名?_Python_Python 3.x_Argparse - Fatal编程技术网

Python3 argparse set_默认值不';不能将字符串作为选项名?

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.

我是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})
您可以使用's
default
参数执行以下操作:

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')