Python 将argparse与接受**kwargs参数的函数一起使用

Python 将argparse与接受**kwargs参数的函数一起使用,python,python-2.7,command-line,argparse,keyword-argument,Python,Python 2.7,Command Line,Argparse,Keyword 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&am

我使用
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的使用,我应该如何设置子Parser

到目前为止,我是如何设置命令行解析器的:

 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
location_by_parser.add_argument("**kwargs", help="**kwargs")
但按照目前的代码,如果我尝试:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
显然,我得到:

argstest.py: error: unrecognized arguments: DISTANCE=3000
但我不知道如何为**kwargs设置子Parser。如果我尝试像这样设置子Parser:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148
location_by_parser.add_argument("**kwargs", help="**kwargs")
然后重试该命令:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
这不起作用,因为
参数
对象(是一个字典)变为:

{'LAT':'40.5949799','LNG':'-73.9495148','command':'location_by_坐标','**kwargs':'DISTANCE=3000'
}

然后返回此回溯:

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
回溯(最近一次呼叫最后一次):
文件“argstest.py”,第118行,在
main()
文件“argstest.py”,第108行,主
foo=位置坐标(**参数)
文件“argstest.py”,第40行,按坐标位置
返回r
UnboundLocalError:赋值前引用了局部变量“r”

如何启用argparse来处理/解析在命令行中输入的内容,这些内容将通过**kwargs传递给函数

你知道这是怎么回事吗

{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'}
参数
字典?您定义了一个名为“**kwargs”('dest')的“位置”参数。你也可以把它命名为“foobar”。解析器将字符串“DISTANCE=3000”分配给
args
命名空间中的该属性,该属性在
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
完全类似的

接受距离之类的东西的正常方式是使用“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
名称空间将具有
距离的默认值。默认值为
None

这是向
argparse
添加
kwarg
类参数的直接方法

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'}
接受任意字典式配对,
distance:3000
distance=3000
,之前已经被要求如此。答案一直是我在上面所画的解析的一些变体。它可以在自定义操作类中完成,也可以按照我的建议进行后期解析

哎呀,这个答案几乎是我几天前写的一个答案的克隆:

2011年的一个类似问题:

=================================

(编辑)

采用
*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'])
因此,我有两个位置参数,一个带有单个字符串值,另一个带有列表(由于
+
nargs)

使用以下属性调用
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']}
我定义了“位置”,但它与“可选”一样有效。位置和选项之间的区别在名称空间中消失

如果将名称空间转换为字典,则可以通过
*args
**kwargs
以各种方式将值传递给
foo
。这一切都取决于我如何调用
foo
,而不是它们在
args
参数中的显示方式。这些都不是
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来处理/解析在 要通过传递给函数的命令行 **夸尔斯

此命令:

$ 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!"
继续分析args,您将看到函数没有被调用。因此,您所有的工作都是徒劳的,您需要通过坐标设置一个名为
location\u的子parser

argparse
模块只检查
sys.argv
,这是一个简单的字符串列表。每个字符串都是在
python
命令之后在命令行中输入的一个“单词”

默认情况下,参数字符串取自sys.argv,…

是的,
sys.argv
是个可怕的名字,但是字符串列表就是字符串列表。如果查看argparse文档,所有示例都会执行以下操作:

parser.parse_args('--foo FOO'.split())
使用
split()
创建的字符串列表与sys.argv引用的一些字符串列表没有什么不同

您需要自己通过坐标()调用
位置函数。为此,您需要从命令行获取arg,将应为kwargs的arg组合到字典中,并按如下方式调用您的函数:

location_by_coordinate(lat, lon, **my_dict)
location_by_parser.add_argument(
    "distance", 
    help="longitude", 
    action=DistanceAction
)
args = parser.parse_args()
args_dict = vars(args)
keyword_args = args_dict["keyword_args"]

location_by_coordinates(lat, lon, **keyword_args)
如果您有这些值:

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'}
您还可以从解析器获取dict:

...
...
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)
location_by_parser.add_argument("distance", help="distance")
如果要创建用户类型:

DISTANCE=3000
在命令行中,首先,我不会让他们键入所有大写字母,因此让我们制定目标:

distance=3000
向解析器添加另一个必需参数:

...
...
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)
location_by_parser.add_argument("distance", help="distance")
然后在解析以下内容之后:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 distance=3000
pieces = args_dict['distance'].split('=')

if len(pieces) == 2 and pieces[0] == 'distance':
    args_dict['distance'] = pieces[1]
您可以这样做:

arguments = parser.parse_args()
args_dict = vars(arguments)
args\u dict
将包含键/值对
'distance':'distance=3000'
。您可以通过执行以下操作将dict条目更改为“距离”:“3000”:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 distance=3000
pieces = args_dict['distance'].split('=')

if len(pieces) == 2 and pieces[0] == 'distance':
    args_dict['distance'] = pieces[1]
或者,您可以进行设置,以便解析器通过创建一个自定义操作自动执行该代码,该操作在
距离