Python3 argparse set_defaults 不将字符串作为选项名称?
Python3 argparse set_defaults doesn't take string as option name?
我是 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
不会。
可以使用字典扩展:
parser.set_defaults(**{NUM: ONE})
您可以使用 argparse
的 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_argument
语句创建的 3 个 Action
对象的指针。我本可以从 pform._group_actions
获得相同的列表,因为这些操作已添加到该组。
通过显式设置 dest
,它是 'num'
而不是 opt
(从长标志派生):
In [40]: alist[0].dest
Out[40]: 'num'
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'
是一个字符串。在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
,也跨越 symbol/string 边界:
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':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
值与 default
值配对的方法。它不一定是字典 key:value
映射。
我是 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
不会。
可以使用字典扩展:
parser.set_defaults(**{NUM: ONE})
您可以使用 argparse
的 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_argument
语句创建的 3 个 Action
对象的指针。我本可以从 pform._group_actions
获得相同的列表,因为这些操作已添加到该组。
通过显式设置 dest
,它是 'num'
而不是 opt
(从长标志派生):
In [40]: alist[0].dest
Out[40]: 'num'
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'
是一个字符串。在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
,也跨越 symbol/string 边界:
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':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
值与 default
值配对的方法。它不一定是字典 key:value
映射。