将 argparse 与采用 **kwargs 参数的函数一起使用
Using argparse with function that takes **kwargs argument
我正在使用 argparse
获取输入并将其传递给以两个变量和 **kwargs
.
作为参数的函数
这是我的函数:
import requests
import sys
import argparse
def location_by_coordinate(LAT, LNG, **kwargs):
if not kwargs:
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
else:
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
for key, value in kwargs.iteritems():
if 'DISTANCE' in kwargs:
distance = kwargs.get('DISTANCE')
if distance > 5000:
print distance
print "max distance is 5000m, value is reassigned to default of 1000m"
distance = 1000
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
else:
pass
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
if 'FACEBOOK_PLACES_ID' in kwargs:
fb_places_id = kwargs.get('FACEBOOK_PLACES_ID')
payload = {'FACEBOOK_PLACES_ID': '%s' % (fb_places_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
if 'FOURSQUARE_ID' in kwargs:
foursquare_id = kwargs.get('FOURSQUARE_ID')
payload = {'FOURSQUARE_ID': '%s' % (foursquare_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
if 'FOURSQUARE_V2_ID' in kwargs:
foursquare_v2_id = kwargs.get('FOURSQUARE_V2_ID')
payload = {'FOURSQUARE_V2_ID': '%s' % (foursquare_v2_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
#print r
return r
鉴于此函数及其对 **kwargs 的使用,我应该如何设置子解析器?
到目前为止,我是这样设置命令行解析器的:
def main():
parser = argparse.ArgumentParser(description="API Endpoints tester")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
location_by_parser = subparsers.add_parser("location_by_coordinate", help="location function")
location_by_parser.add_argument("LAT", help="latitude")
location_by_parser.add_argument("LNG", help="longitude")
arguments = parser.parse_args(sys.argv[1:])
arguments = vars(arguments)
command = arguments.pop("command")
if command == "location_by_coordinate":
LAT, LNG = location_by_coordinate(**arguments)
else:
print "No command provided..."
if __name__ == "__main__":
main()
显然,当我在命令行调用它时,上面的 main() 函数与 location_by_coordinate() 函数一起工作正常:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148
但是使用当前的代码,如果我尝试:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
显然,我得到:
argstest.py: error: unrecognized arguments: DISTANCE=3000
但我不确定如何为 **kwargs 设置子解析器。如果我尝试像这样设置子解析器:
location_by_parser.add_argument("**kwargs", help="**kwargs")
然后再次尝试该命令:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
那是行不通的,因为 arguments
对象(它是一个字典)变成了这个:
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'
}
并返回此 Traceback:
Traceback (most recent call last):
File "argstest.py", line 118, in <module>
main()
File "argstest.py", line 108, in main
foo = location_by_coordinate(**arguments)
File "argstest.py", line 40, in location_by_coordinate
return r
UnboundLocalError: local variable 'r' referenced before assignment
如何启用 argparse 以 handle/to 解析在命令行中输入的内容,这些内容旨在通过 **kwargs 传递给函数?
你明白
是怎么回事吗
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'}
arguments
字典?您定义了一个 'positional' 参数,其名称 ('dest') 为“**kwargs”。您也可以将其命名为 'foobar'。解析器将字符串 'DISTANCE=3000' 分配给 args
命名空间中的该属性,该属性在 arguments
.
中变成字典 key:value 对
当然,您可以查找 arguments['**kwargs']
,然后自己解析该值:
v = arguments['**kwargs'] # or pop if you prefer
if v is not None:
k, v = v.split('=')
arguments[k] = int(v)
它可以被推广来处理多对(用 `nargs='*' 定义)。
argparse
处理参数的方式与 Python 函数不同,因此与 **kwargs
.
没有任何相似之处
接受类似 distance
的正常方法是使用 'optionals' 或带标记的参数。
parser.add_argument('-d','--distance', type=int, help=...)
哪个会接受
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --distance=3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --distance 3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --d3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148
它也可以设置为使用 --DISTANCE
或其他名称。在最后一种情况下,args
命名空间将具有 distance
的默认值。默认默认为None
.
这是向 argparse
添加 kwarg
类参数的直接方法。
接受任意字典,如对 distance:3000
、distance=3000
,之前已在 SO 上询问过。答案一直是我上面概述的解析的一些变体。它可以在自定义操作 class 中完成,或者按照我的建议 post 解析。
哎呀,这个答案几乎是我几天前写的答案的克隆:
一个类似的 2011 问题:
Using argparse to parse arguments of form "arg= val"
=================================
(编辑)
函数示例 *args
:
In [2]: import argparse
In [3]: def foo(*args, **kwargs):
...: print('args',args)
...: print('kwargs',kwargs)
...:
In [4]: parser=argparse.ArgumentParser()
In [5]: parser.add_argument('arg1')
In [6]: parser.add_argument('arg2',nargs='+')
In [7]: args=parser.parse_args('one two three'.split())
In [8]: args
Out[8]: Namespace(arg1='one', arg2=['two', 'three'])
所以我有 2 个位置参数,一个有一个字符串值,另一个有一个列表(由于 +
nargs)。
使用这些 args
属性调用 foo
:
In [10]: foo(args.arg1)
args ('one',)
kwargs {}
In [11]: foo(args.arg1, args.arg2)
args ('one', ['two', 'three'])
kwargs {}
In [12]: foo(args.arg1, arg2=args.arg2)
args ('one',)
kwargs {'arg2': ['two', 'three']}
我定义了 'positionals',但它与 'optionals' 一样有效。位置变量和可选变量之间的区别在名称空间中消失了。
如果我将命名空间转换为字典,我可以通过 *args
或 **kwargs
等多种方式将值传递给 foo
。这完全取决于我如何称呼 foo
,而不是它们在 args
或 arguments
中的显示方式。 None 这是 argparse
独有的。
In [13]: arguments = vars(args)
In [14]: arguments
Out[14]: {'arg2': ['two', 'three'], 'arg1': 'one'}
In [15]: foo(arguments['arg2'], arguments['arg1'])
args (['two', 'three'], 'one')
kwargs {}
In [16]: foo(arguments['arg2'], arguments)
args (['two', 'three'], {'arg2': ['two', 'three'], 'arg1': 'one'})
kwargs {}
In [17]: foo(arguments['arg2'], **arguments)
args (['two', 'three'],)
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
In [24]: foo(*arguments, **arguments)
args ('arg2', 'arg1') # *args is the keys of arguments
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
In [25]: foo(*arguments.values(), **arguments)
args (['two', 'three'], 'one') # *args is the values of arguments
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
How can I enable argparse to handle/to parse what is entered at the
command line that is intended to be passed to the function via
**kwargs?
这个命令:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
不执行函数调用:
location_by_coordinate(40.5949799, -73.9495148, DISTANCE=3000)
这很容易证明:
def location_by_coordinate(x, y, **kwargs):
print "I was called!"
继续解析参数,您会发现函数没有被调用。结果,您设置名称为 location_by_coordinate
的子解析器的所有工作都是徒劳的。
argparse
模块只检查 sys.argv
,这是一个简单的字符串列表。每个字符串都是在 python
命令之后在命令行中输入的 'words' 之一。
By default, the argument strings are taken from sys.argv,...
https://docs.python.org/3/library/argparse.html#the-parse-args-method
是的,sys.argv
是一个可怕的名字,但是字符串列表只是字符串列表。如果您查看 argparse 文档,所有示例都会这样做:
parser.parse_args('--foo FOO'.split())
您使用 split()
创建的字符串列表与 sys.argv 引用的某些字符串列表没有什么不同。
您需要自己调用 location_by_coordinate()
函数。为此,您需要从命令行获取 args,assemble 应该是字典中的 kwargs 的 args,然后像这样调用您的函数:
location_by_coordinate(lat, lon, **my_dict)
如果您有这些值:
lat = 10
lon = 20
my_dict = {'a': 1, 'b': 2}
那么上面的函数调用将等同于:
location_by_coordinate(10, 20, a=1, b=2)
这是一个例子:
import argparse
def dostuff(x, y, **kwargs):
print x, y, kwargs
parser = argparse.ArgumentParser()
parser.add_argument("LAT")
parser.add_argument("LON")
parser.add_argument("--distance")
args = parser.parse_args()
my_dict = {}
my_dict["distance"] = args.distance
dostuff(args.LAT, args.LON, **my_dict)
$ python my_prog.py 10 20 --distance 1
10 20 {'distance': '1'}
您还可以从解析器中获取字典:
...
...
args = parser.parse_args()
args_dict = vars(args)
print args_dict
--output:--
{'LAT': '10', 'distance': '1', 'LON': '20'}
lat = args_dict.pop('LAT')
lon = args_dict.pop('LON')
print args_dict
--output:--
{'distance': '1'}
location_by_coordinates(lat, lon, **args_dict)
如果你想让用户输入:
DISTANCE=3000
在命令行上,首先我不会让他们输入全部大写,所以让我们设定目标:
distance=3000
向解析器添加另一个强制参数:
location_by_parser.add_argument("distance", help="distance")
然后在你解析以下内容后:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 distance=3000
你可以这样做:
arguments = parser.parse_args()
args_dict = vars(arguments)
args_dict
将包含 key/value 对 'distance': 'distance=3000'
。您可以通过执行以下操作将该字典条目更改为 'distance': '3000'
:
pieces = args_dict['distance'].split('=')
if len(pieces) == 2 and pieces[0] == 'distance':
args_dict['distance'] = pieces[1]
或者,您可以进行设置,以便解析器通过创建在解析 distance
arg 时执行的自定义操作来自动执行该代码:
class DistanceAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
#values => The value for the distance command line arg
pieces = values.split('=')
if len(pieces) == 2 and pieces[0] in ['distance', 'wave_action']: #only allow 'distance=' and 'wave_action='
setattr(namespace, self.dest, pieces[1]) #The dest key specified in the parser gets assigned the value
else:
raise argparse.ArgumentTypeError('Usage: distance=3000. Only distance=, wave_action= allowed.')
您可以使用这样的操作:
location_by_parser.add_argument(
"distance",
help="longitude",
action=DistanceAction
)
如果你想更有趣,你可以将命令行上指定的所有 name=val
args 收集到一个名为 keyword_args
的字典中,这样你就可以调用你的方法像这样:
args = parser.parse_args()
args_dict = vars(args)
keyword_args = args_dict["keyword_args"]
location_by_coordinates(lat, lon, **keyword_args)
解析器配置如下:
location_by_parser.add_argument(
"keyword_args",
help="extra args",
nargs='*',
action=DistanceAction
)
import argparse
import sys
def location_by_coordinates(x, y, **kwargs):
print x
print y
print kwargs
class DistanceAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
allowed_keywords = ['distance', 'wave_action']
keyword_dict = {}
for arg in values: #values => The args found for keyword_args
pieces = arg.split('=')
if len(pieces) == 2 and pieces[0] in allowed_keywords:
keyword_dict[pieces[0]] = pieces[1]
else: #raise an error
#Create error message:
msg_inserts = ['{}='] * len(allowed_keywords)
msg_template = 'Example usage: distance=3000. Only {} allowed.'.format(', '.join(msg_inserts))
msg = msg_template.format(*allowed_keywords)
raise argparse.ArgumentTypeError(msg)
setattr(namespace, self.dest, keyword_dict) #The dest key specified in the
#parser gets assigned the keyword_dict--in
#this case it defaults to 'keyword_args'
parser = argparse.ArgumentParser(description="API Endpoints tester")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
location_by_parser = subparsers.add_parser("location_by_coordinate", help="location function")
location_by_parser.add_argument("LAT", help="latitude")
location_by_parser.add_argument("LNG", help="longitude")
location_by_parser.add_argument("keyword_args", help="extra args", nargs='*', action=DistanceAction)
arguments = parser.parse_args()
args_dict = vars(arguments)
print args_dict
lat = args_dict['LAT']
lon = args_dict['LNG']
keyword_args = args_dict['keyword_args']
location_by_coordinates(lat, lon, **keyword_args)
示例:
$ python prog.py location_by_coordinate 40.5949799 -73.9495148 distance=3000 wave_action=1.4
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', 'keyword_args': {'distance': '3000', 'wave_action': '1.4'}}
40.5949799
-73.9495148
{'distance': '3000', 'wave_action': '1.4'}
$ python prog.py location_by_coordinate 40.5949799 -73.9495148 x=10
...
...
File "2.py", line 25, in __call__
raise argparse.ArgumentTypeError(msg)
argparse.ArgumentTypeError: Example usage: distance=3000. Only distance=, wave_action= allowed.
我正在使用 argparse
获取输入并将其传递给以两个变量和 **kwargs
.
这是我的函数:
import requests
import sys
import argparse
def location_by_coordinate(LAT, LNG, **kwargs):
if not kwargs:
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
else:
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
for key, value in kwargs.iteritems():
if 'DISTANCE' in kwargs:
distance = kwargs.get('DISTANCE')
if distance > 5000:
print distance
print "max distance is 5000m, value is reassigned to default of 1000m"
distance = 1000
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
else:
pass
coordinate_url = "https://api.instagram.com/v1/locations/search?lat=%s&lng=%s&access_token=%s" % (LAT, LNG, current_token)
r = requests.get(coordinate_url).text
if 'FACEBOOK_PLACES_ID' in kwargs:
fb_places_id = kwargs.get('FACEBOOK_PLACES_ID')
payload = {'FACEBOOK_PLACES_ID': '%s' % (fb_places_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
if 'FOURSQUARE_ID' in kwargs:
foursquare_id = kwargs.get('FOURSQUARE_ID')
payload = {'FOURSQUARE_ID': '%s' % (foursquare_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
if 'FOURSQUARE_V2_ID' in kwargs:
foursquare_v2_id = kwargs.get('FOURSQUARE_V2_ID')
payload = {'FOURSQUARE_V2_ID': '%s' % (foursquare_v2_id), 'DISTANCE': '%s' % (DISTANCE)}
r = requests.get(coordinate_url, params=payload).text
#print r
return r
鉴于此函数及其对 **kwargs 的使用,我应该如何设置子解析器?
到目前为止,我是这样设置命令行解析器的:
def main():
parser = argparse.ArgumentParser(description="API Endpoints tester")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
location_by_parser = subparsers.add_parser("location_by_coordinate", help="location function")
location_by_parser.add_argument("LAT", help="latitude")
location_by_parser.add_argument("LNG", help="longitude")
arguments = parser.parse_args(sys.argv[1:])
arguments = vars(arguments)
command = arguments.pop("command")
if command == "location_by_coordinate":
LAT, LNG = location_by_coordinate(**arguments)
else:
print "No command provided..."
if __name__ == "__main__":
main()
显然,当我在命令行调用它时,上面的 main() 函数与 location_by_coordinate() 函数一起工作正常:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148
但是使用当前的代码,如果我尝试:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
显然,我得到:
argstest.py: error: unrecognized arguments: DISTANCE=3000
但我不确定如何为 **kwargs 设置子解析器。如果我尝试像这样设置子解析器:
location_by_parser.add_argument("**kwargs", help="**kwargs")
然后再次尝试该命令:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
那是行不通的,因为 arguments
对象(它是一个字典)变成了这个:
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'
}
并返回此 Traceback:
Traceback (most recent call last):
File "argstest.py", line 118, in <module>
main()
File "argstest.py", line 108, in main
foo = location_by_coordinate(**arguments)
File "argstest.py", line 40, in location_by_coordinate
return r
UnboundLocalError: local variable 'r' referenced before assignment
如何启用 argparse 以 handle/to 解析在命令行中输入的内容,这些内容旨在通过 **kwargs 传递给函数?
你明白
是怎么回事吗{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'}
arguments
字典?您定义了一个 'positional' 参数,其名称 ('dest') 为“**kwargs”。您也可以将其命名为 'foobar'。解析器将字符串 'DISTANCE=3000' 分配给 args
命名空间中的该属性,该属性在 arguments
.
当然,您可以查找 arguments['**kwargs']
,然后自己解析该值:
v = arguments['**kwargs'] # or pop if you prefer
if v is not None:
k, v = v.split('=')
arguments[k] = int(v)
它可以被推广来处理多对(用 `nargs='*' 定义)。
argparse
处理参数的方式与 Python 函数不同,因此与 **kwargs
.
接受类似 distance
的正常方法是使用 'optionals' 或带标记的参数。
parser.add_argument('-d','--distance', type=int, help=...)
哪个会接受
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --distance=3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --distance 3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148 --d3000
python argstest.py location_by_coordinate 40.5949799 -73.9495148
它也可以设置为使用 --DISTANCE
或其他名称。在最后一种情况下,args
命名空间将具有 distance
的默认值。默认默认为None
.
这是向 argparse
添加 kwarg
类参数的直接方法。
接受任意字典,如对 distance:3000
、distance=3000
,之前已在 SO 上询问过。答案一直是我上面概述的解析的一些变体。它可以在自定义操作 class 中完成,或者按照我的建议 post 解析。
哎呀,这个答案几乎是我几天前写的答案的克隆:
一个类似的 2011 问题: Using argparse to parse arguments of form "arg= val"
=================================
(编辑)
函数示例 *args
:
In [2]: import argparse
In [3]: def foo(*args, **kwargs):
...: print('args',args)
...: print('kwargs',kwargs)
...:
In [4]: parser=argparse.ArgumentParser()
In [5]: parser.add_argument('arg1')
In [6]: parser.add_argument('arg2',nargs='+')
In [7]: args=parser.parse_args('one two three'.split())
In [8]: args
Out[8]: Namespace(arg1='one', arg2=['two', 'three'])
所以我有 2 个位置参数,一个有一个字符串值,另一个有一个列表(由于 +
nargs)。
使用这些 args
属性调用 foo
:
In [10]: foo(args.arg1)
args ('one',)
kwargs {}
In [11]: foo(args.arg1, args.arg2)
args ('one', ['two', 'three'])
kwargs {}
In [12]: foo(args.arg1, arg2=args.arg2)
args ('one',)
kwargs {'arg2': ['two', 'three']}
我定义了 'positionals',但它与 'optionals' 一样有效。位置变量和可选变量之间的区别在名称空间中消失了。
如果我将命名空间转换为字典,我可以通过 *args
或 **kwargs
等多种方式将值传递给 foo
。这完全取决于我如何称呼 foo
,而不是它们在 args
或 arguments
中的显示方式。 None 这是 argparse
独有的。
In [13]: arguments = vars(args)
In [14]: arguments
Out[14]: {'arg2': ['two', 'three'], 'arg1': 'one'}
In [15]: foo(arguments['arg2'], arguments['arg1'])
args (['two', 'three'], 'one')
kwargs {}
In [16]: foo(arguments['arg2'], arguments)
args (['two', 'three'], {'arg2': ['two', 'three'], 'arg1': 'one'})
kwargs {}
In [17]: foo(arguments['arg2'], **arguments)
args (['two', 'three'],)
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
In [24]: foo(*arguments, **arguments)
args ('arg2', 'arg1') # *args is the keys of arguments
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
In [25]: foo(*arguments.values(), **arguments)
args (['two', 'three'], 'one') # *args is the values of arguments
kwargs {'arg2': ['two', 'three'], 'arg1': 'one'}
How can I enable argparse to handle/to parse what is entered at the command line that is intended to be passed to the function via **kwargs?
这个命令:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
不执行函数调用:
location_by_coordinate(40.5949799, -73.9495148, DISTANCE=3000)
这很容易证明:
def location_by_coordinate(x, y, **kwargs):
print "I was called!"
继续解析参数,您会发现函数没有被调用。结果,您设置名称为 location_by_coordinate
的子解析器的所有工作都是徒劳的。
argparse
模块只检查 sys.argv
,这是一个简单的字符串列表。每个字符串都是在 python
命令之后在命令行中输入的 'words' 之一。
By default, the argument strings are taken from sys.argv,...
https://docs.python.org/3/library/argparse.html#the-parse-args-method
是的,sys.argv
是一个可怕的名字,但是字符串列表只是字符串列表。如果您查看 argparse 文档,所有示例都会这样做:
parser.parse_args('--foo FOO'.split())
您使用 split()
创建的字符串列表与 sys.argv 引用的某些字符串列表没有什么不同。
您需要自己调用 location_by_coordinate()
函数。为此,您需要从命令行获取 args,assemble 应该是字典中的 kwargs 的 args,然后像这样调用您的函数:
location_by_coordinate(lat, lon, **my_dict)
如果您有这些值:
lat = 10
lon = 20
my_dict = {'a': 1, 'b': 2}
那么上面的函数调用将等同于:
location_by_coordinate(10, 20, a=1, b=2)
这是一个例子:
import argparse
def dostuff(x, y, **kwargs):
print x, y, kwargs
parser = argparse.ArgumentParser()
parser.add_argument("LAT")
parser.add_argument("LON")
parser.add_argument("--distance")
args = parser.parse_args()
my_dict = {}
my_dict["distance"] = args.distance
dostuff(args.LAT, args.LON, **my_dict)
$ python my_prog.py 10 20 --distance 1
10 20 {'distance': '1'}
您还可以从解析器中获取字典:
...
...
args = parser.parse_args()
args_dict = vars(args)
print args_dict
--output:--
{'LAT': '10', 'distance': '1', 'LON': '20'}
lat = args_dict.pop('LAT')
lon = args_dict.pop('LON')
print args_dict
--output:--
{'distance': '1'}
location_by_coordinates(lat, lon, **args_dict)
如果你想让用户输入:
DISTANCE=3000
在命令行上,首先我不会让他们输入全部大写,所以让我们设定目标:
distance=3000
向解析器添加另一个强制参数:
location_by_parser.add_argument("distance", help="distance")
然后在你解析以下内容后:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 distance=3000
你可以这样做:
arguments = parser.parse_args()
args_dict = vars(arguments)
args_dict
将包含 key/value 对 'distance': 'distance=3000'
。您可以通过执行以下操作将该字典条目更改为 'distance': '3000'
:
pieces = args_dict['distance'].split('=')
if len(pieces) == 2 and pieces[0] == 'distance':
args_dict['distance'] = pieces[1]
或者,您可以进行设置,以便解析器通过创建在解析 distance
arg 时执行的自定义操作来自动执行该代码:
class DistanceAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
#values => The value for the distance command line arg
pieces = values.split('=')
if len(pieces) == 2 and pieces[0] in ['distance', 'wave_action']: #only allow 'distance=' and 'wave_action='
setattr(namespace, self.dest, pieces[1]) #The dest key specified in the parser gets assigned the value
else:
raise argparse.ArgumentTypeError('Usage: distance=3000. Only distance=, wave_action= allowed.')
您可以使用这样的操作:
location_by_parser.add_argument(
"distance",
help="longitude",
action=DistanceAction
)
如果你想更有趣,你可以将命令行上指定的所有 name=val
args 收集到一个名为 keyword_args
的字典中,这样你就可以调用你的方法像这样:
args = parser.parse_args()
args_dict = vars(args)
keyword_args = args_dict["keyword_args"]
location_by_coordinates(lat, lon, **keyword_args)
解析器配置如下:
location_by_parser.add_argument(
"keyword_args",
help="extra args",
nargs='*',
action=DistanceAction
)
import argparse
import sys
def location_by_coordinates(x, y, **kwargs):
print x
print y
print kwargs
class DistanceAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
allowed_keywords = ['distance', 'wave_action']
keyword_dict = {}
for arg in values: #values => The args found for keyword_args
pieces = arg.split('=')
if len(pieces) == 2 and pieces[0] in allowed_keywords:
keyword_dict[pieces[0]] = pieces[1]
else: #raise an error
#Create error message:
msg_inserts = ['{}='] * len(allowed_keywords)
msg_template = 'Example usage: distance=3000. Only {} allowed.'.format(', '.join(msg_inserts))
msg = msg_template.format(*allowed_keywords)
raise argparse.ArgumentTypeError(msg)
setattr(namespace, self.dest, keyword_dict) #The dest key specified in the
#parser gets assigned the keyword_dict--in
#this case it defaults to 'keyword_args'
parser = argparse.ArgumentParser(description="API Endpoints tester")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
location_by_parser = subparsers.add_parser("location_by_coordinate", help="location function")
location_by_parser.add_argument("LAT", help="latitude")
location_by_parser.add_argument("LNG", help="longitude")
location_by_parser.add_argument("keyword_args", help="extra args", nargs='*', action=DistanceAction)
arguments = parser.parse_args()
args_dict = vars(arguments)
print args_dict
lat = args_dict['LAT']
lon = args_dict['LNG']
keyword_args = args_dict['keyword_args']
location_by_coordinates(lat, lon, **keyword_args)
示例:
$ python prog.py location_by_coordinate 40.5949799 -73.9495148 distance=3000 wave_action=1.4
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', 'keyword_args': {'distance': '3000', 'wave_action': '1.4'}}
40.5949799
-73.9495148
{'distance': '3000', 'wave_action': '1.4'}
$ python prog.py location_by_coordinate 40.5949799 -73.9495148 x=10
...
...
File "2.py", line 25, in __call__
raise argparse.ArgumentTypeError(msg)
argparse.ArgumentTypeError: Example usage: distance=3000. Only distance=, wave_action= allowed.