使用argparse函数接受** kwargs参数 [英] Using argparse with function that takes **kwargs argument
问题描述
我使用 argparse
接受输入,并将其传递给一个函数,它接受两个变量和 ** kwargs
。
I'm using argparse
to take input and pass it to a function that takes as arguments two variables and **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
Given this function and its use of **kwargs, how should I setup the subparsers?
以下是我迄今为止设置命令行解析器的方法:
Here's how I've setup the command line parser thus far:
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()函数一样正常:
Obviously, the above main() function works fine with the location_by_coordinate() function when I call it at the command line like this:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148
但是使用代码的方式,如果我尝试:
But with the code the way it is currently, if I try:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
显然,我得到:
argstest.py: error: unrecognized arguments: DISTANCE=3000
但我不知道如何设置** kwargs的子分析。如果我尝试这样设置一个子分析器:
But I'm not sure how to setup a subparser for **kwargs. If I try to setup a subparser like this:
location_by_parser.add_argument("**kwargs", help="**kwargs")
,然后再次尝试该命令:
and then try that command again:
$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
这不工作,因为 arguments
对象(这是一个字典),变成这样:
That doesn't work because the arguments
object (which is a dictionary), becomes this:
{'LAT':'40 .5949799','LNG':'-73.9495148','command':'location_by_coordinate','** kwargs':'DISTANCE = 3000'
}
并返回此Traceback:
And this Traceback is returned:
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处理/解析在命令行输入的是要通过** kwargs传递到函数?
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?
推荐答案
您是否了解
{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'}
arguments
您使用'** kwargs'的名称('dest')定义了一个positions参数。你可以把它命名为foobar。解析器为 args
命名空间中的该属性分配了字符串DISTANCE = 3000,该命名空间变成了 arguments中的字典键值对: code>。
arguments
dictionary? You defined a 'positional' argument with the name ('dest') of '**kwargs'. You could just as well named it 'foobar'. The parser assigned the string 'DISTANCE=3000' to that attribute in the args
namespace, which turned into a dictionary key:value pair in arguments
.
你当然可以查找 arguments ['** kwargs']
,并解析自己的值:
You could, of course, look for arguments['**kwargs']
, and parse the value for yourself:
v = arguments['**kwargs'] # or pop if you prefer
if v is not None:
k, v = v.split('=')
arguments[k] = int(v)
可以概括为处理多个对(用`nargs ='*'定义)。
It could be generalized to handle multiple pairs (defined with `nargs='*').
argparse
不像Python函数那样处理参数,所以没有什么完全类似于 ** kwargs 。
argparse
does not handle arguments the same way as Python functions, so there's nothing exactly analogous the **kwargs
.
接受 distance
的常规方法是使用'optionals'标记的参数。
The normal way to accept something like distance
is with 'optionals' or flagged arguments.
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
。
It could also be setup to use --DISTANCE
or other names. In the last case args
namespace will have a default value for distance
. The default default is None
.
这是添加 kwarg
像
argparse
的参数。
接受任意字典对,距离:3000
, distance = 3000
答案总是一些分析的变化我上面草图。它可以在自定义Action类中完成,或者按照我的建议进行后处理。
Accepting arbitrary dictionary like pairs, distance:3000
, distance=3000
, has been asked before on SO. The answers have always been some variation of the parsing that I sketched above. It could be done in a custom Action class, or post parsing as I suggest.
oops,这个答案几乎是我几天前写的一个克隆:
http://stackoverflow.com/a/33639147/901925
oops, this answer is nearly a clone of one I wrote a few days ago: http://stackoverflow.com/a/33639147/901925
类似的2011问题:
使用argparse解析形式为arg = val的参数
A similar 2011 question: 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)。
So I have 2 positional arguments, one with a single string value, the other with a list (due to the +
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'。 positionals和optionals之间的区别在命名空间中消失。
I defined 'positionals', but it would have worked just as well with 'optionals'. The distinction between positionals and optionals disappears in the namespace.
如果我将命名空间转换为字典,我可以通过各种方式传递值到 foo
* args
或通过 ** kwargs
。这一切都在我如何调用 foo
,而不是它们如何在 args
或参数
。这不是 argparse
独有的。
If I convert the namespace to a dictionary, I can pass values to foo
in various ways, either through the *args
or through **kwargs
. It's all in how I call foo
, not in how they appear in args
or arguments
. None of this is unique to 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'}
这篇关于使用argparse函数接受** kwargs参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!