巧妙地将位置参数作为 args 和可选参数作为 kwargs 从 argparse 传递给函数
Neatly pass positional arguments as args and optional arguments as kwargs from argparse to a function
我想编写一个 Python 脚本,通过 argparse
:
接受一些必要的位置参数和一些可选的命令行参数
- 让我们调用位置参数
a
、b
、c
和可选参数 x
、y
、z
。
- 在我的 Python 脚本中,我想将这些参数传递给一个函数;具体来说,我希望
a
、b
、c
作为 *args
传递,而 x
、y
、z
传递给作为 **kwargs
传递,后者保留其名称。
- 我想用不同的函数和不同数量的位置参数和可选参数多次执行此操作。有没有一种简洁、灵活、and/or pythonic 的方式来做到这一点?
下面是一些示例代码:
import argparse
def parse():
parser = argparse.ArgumentParser()
parser.add_argument('a', help='1st arg')
parser.add_argument('b', help='2nd arg')
parser.add_argument('c', help='3rd arg')
parser.add_argument('-x', '--x', help='1st kwarg')
parser.add_argument('-y', '--y', help='2nd kwarg')
parser.add_argument('-z', '--z', help='3rd kwarg')
return parser.parse_args()
def func(*args, **kwargs):
a, b, c = args
print 'a=', a
print 'b=', b
print 'c=', c
for k, v in kwargs.iteritems():
print '%s=' % k, v
if __name__ == '__main__':
all_args = parse()
### need to split all_args into args and kwargs here ###
func(*args, **kwargs)
您从 parse_args
返回的 Namespace
将具有与您的每个参数相对应的属性。位置参数和可选参数之间没有区别,例如:
args
Namespace(a='1',b='one',x='foo', y=...)
如有详细记录,可以通过以下方式访问:
args.a
args.x
etc.
Namespace
也可以变成字典:
vars(args)
{'a'='1', 'b'='one', etc.}
您可以将字典作为 **kwargs
传递给函数。这是标准的 Python 论证实践。
如果你想将一些参数作为 *args
传递,你必须自己将它们从 Namespace
或字典中分离出来。 argparse
中的任何内容都无法为您做到这一点。
您可以编写如下函数(未测试):
def split_args(args):
vargs = vars(args)
alist = ['a','b','c']
args1 = []
for a in alist:
v = vargs.pop(a)
args1.append(v)
return args1, vars
或者更简洁,将 pop
放在列表理解中:
In [702]: vargs = dict(a=1,b=3,c=4,x=5,y=3,z=3)
In [703]: [vargs.pop(a) for a in ['a','b','c']]
Out[703]: [1, 3, 4]
In [704]: vargs
Out[704]: {'y': 3, 'x': 5, 'z': 3}
In [705]: def foo(*args,**kwargs):
.....: print(args)
.....: print(kwargs)
.....:
In [706]: vargs = dict(a=1,b=3,c=4,x=5,y=3,z=3)
In [707]: foo(*[vargs.pop(a) for a in ['a','b','c']],**vargs)
(1, 3, 4)
{'x': 5, 'z': 3, 'y': 3}
使用自定义操作的进一步想法 class
parser
通过其 option_strings
属性确定参数是 optional
还是 positional
。 add_argument
returns 一个 Action
subclass,其属性如下:
MyAction(option_strings=[], dest='baz', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
这是一个 positional
因为 option_strings
是一个空列表。
MyAction(option_strings=['-m', '--mew'], dest='mew', nargs=None,...)
是一个 optional
,因为该列表不为空。
解析器将输入字符串与 option_strings
和 nargs
匹配,然后将值传递给匹配 Action
的 __call__
方法。此方法定义如下:
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
这是默认的 store
操作。这些值作为 dest
属性放在 Namespace
中。
option_string
参数是触发此调用的字符串,类似于“-m”或“--mew”,或者 None
用于 positional
。定义的动作类型不使用这个,但是 user-defined 动作 class 可以做一些事情。
class MyAction(argparse._StoreAction):
def __call__(self, parser, namespace, values, option_string=None):
# store option_string along with values in the Namespace
setattr(namespace, self.dest, [values,option_string])
或者你可以用 positionals
做一些特别的事情,例如
if option_string is None:
# append values to a `star_args` attribute
# rather than self.dest
像这样的操作 positionals
可以在解析后访问:
args.star_args
解析器确实维护了这样一个列表属性。 parse_known_args
returns的extras
临时存放在'_UNRECOGNIZED_ARGS_ATTR'属性中的Namespace
我想编写一个 Python 脚本,通过 argparse
:
- 让我们调用位置参数
a
、b
、c
和可选参数x
、y
、z
。 - 在我的 Python 脚本中,我想将这些参数传递给一个函数;具体来说,我希望
a
、b
、c
作为*args
传递,而x
、y
、z
传递给作为**kwargs
传递,后者保留其名称。 - 我想用不同的函数和不同数量的位置参数和可选参数多次执行此操作。有没有一种简洁、灵活、and/or pythonic 的方式来做到这一点?
下面是一些示例代码:
import argparse
def parse():
parser = argparse.ArgumentParser()
parser.add_argument('a', help='1st arg')
parser.add_argument('b', help='2nd arg')
parser.add_argument('c', help='3rd arg')
parser.add_argument('-x', '--x', help='1st kwarg')
parser.add_argument('-y', '--y', help='2nd kwarg')
parser.add_argument('-z', '--z', help='3rd kwarg')
return parser.parse_args()
def func(*args, **kwargs):
a, b, c = args
print 'a=', a
print 'b=', b
print 'c=', c
for k, v in kwargs.iteritems():
print '%s=' % k, v
if __name__ == '__main__':
all_args = parse()
### need to split all_args into args and kwargs here ###
func(*args, **kwargs)
您从 parse_args
返回的 Namespace
将具有与您的每个参数相对应的属性。位置参数和可选参数之间没有区别,例如:
args
Namespace(a='1',b='one',x='foo', y=...)
如有详细记录,可以通过以下方式访问:
args.a
args.x
etc.
Namespace
也可以变成字典:
vars(args)
{'a'='1', 'b'='one', etc.}
您可以将字典作为 **kwargs
传递给函数。这是标准的 Python 论证实践。
如果你想将一些参数作为 *args
传递,你必须自己将它们从 Namespace
或字典中分离出来。 argparse
中的任何内容都无法为您做到这一点。
您可以编写如下函数(未测试):
def split_args(args):
vargs = vars(args)
alist = ['a','b','c']
args1 = []
for a in alist:
v = vargs.pop(a)
args1.append(v)
return args1, vars
或者更简洁,将 pop
放在列表理解中:
In [702]: vargs = dict(a=1,b=3,c=4,x=5,y=3,z=3)
In [703]: [vargs.pop(a) for a in ['a','b','c']]
Out[703]: [1, 3, 4]
In [704]: vargs
Out[704]: {'y': 3, 'x': 5, 'z': 3}
In [705]: def foo(*args,**kwargs):
.....: print(args)
.....: print(kwargs)
.....:
In [706]: vargs = dict(a=1,b=3,c=4,x=5,y=3,z=3)
In [707]: foo(*[vargs.pop(a) for a in ['a','b','c']],**vargs)
(1, 3, 4)
{'x': 5, 'z': 3, 'y': 3}
使用自定义操作的进一步想法 class
parser
通过其 option_strings
属性确定参数是 optional
还是 positional
。 add_argument
returns 一个 Action
subclass,其属性如下:
MyAction(option_strings=[], dest='baz', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
这是一个 positional
因为 option_strings
是一个空列表。
MyAction(option_strings=['-m', '--mew'], dest='mew', nargs=None,...)
是一个 optional
,因为该列表不为空。
解析器将输入字符串与 option_strings
和 nargs
匹配,然后将值传递给匹配 Action
的 __call__
方法。此方法定义如下:
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
这是默认的 store
操作。这些值作为 dest
属性放在 Namespace
中。
option_string
参数是触发此调用的字符串,类似于“-m”或“--mew”,或者 None
用于 positional
。定义的动作类型不使用这个,但是 user-defined 动作 class 可以做一些事情。
class MyAction(argparse._StoreAction):
def __call__(self, parser, namespace, values, option_string=None):
# store option_string along with values in the Namespace
setattr(namespace, self.dest, [values,option_string])
或者你可以用 positionals
做一些特别的事情,例如
if option_string is None:
# append values to a `star_args` attribute
# rather than self.dest
像这样的操作 positionals
可以在解析后访问:
args.star_args
解析器确实维护了这样一个列表属性。 parse_known_args
returns的extras
临时存放在'_UNRECOGNIZED_ARGS_ATTR'属性中的Namespace