使用带有**kwargs参数的函数的argparse

Adj*_*con 5 python command-line kwargs python-2.7 argparse

我正在使用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
Run Code Online (Sandbox Code Playgroud)

鉴于此功能及其使用**kwargs,我应该如何设置subparsers?

这是我到目前为止设置命令行解析器的方法:

 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()
Run Code Online (Sandbox Code Playgroud)

显然,当我在命令行中调用它时,上面的main()函数可以正常使用location_by_coordinate()函数:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148
Run Code Online (Sandbox Code Playgroud)

但是代码的方式与目前一样,如果我尝试:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
Run Code Online (Sandbox Code Playgroud)

显然,我得到:

argstest.py: error: unrecognized arguments: DISTANCE=3000
Run Code Online (Sandbox Code Playgroud)

但我不确定如何为**kwargs设置subparser.如果我尝试设置这样的subparser:

location_by_parser.add_argument("**kwargs", help="**kwargs")
Run Code Online (Sandbox Code Playgroud)

然后再次尝试该命令:

$ python argstest.py location_by_coordinate 40.5949799 -73.9495148 DISTANCE=3000
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为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
Run Code Online (Sandbox Code Playgroud)

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

hpa*_*ulj 8

你明白发生了什么吗?

{'LAT': '40.5949799', 'LNG': '-73.9495148', 'command': 'location_by_coordinate', '**kwargs': 'DISTANCE=3000'}
Run Code Online (Sandbox Code Playgroud)

arguments字典?您使用'**kwargs'的名称('dest')定义了一个'位置'参数.你可以把它命名为'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)
Run Code Online (Sandbox Code Playgroud)

它可以推广到处理多对(用`nargs ='*'定义).


argparse不像Python函数那样处理参数,所以没有什么完全类似的**kwargs.

接受类似事件的正常方式distance是使用'optionals'或标记参数.

parser.add_argument('-d','--distance', type=int, help=...)
Run Code Online (Sandbox Code Playgroud)

哪个会接受

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
Run Code Online (Sandbox Code Playgroud)

它也可以设置为使用--DISTANCE或其他名称.在最后一种情况下,args命名空间将具有默认值distance.默认默认值为None.

这是添加kwarg类似参数的直接方式argparse.

接受任意词典像对,distance:3000,distance=3000,一直这样要求之前.答案一直是我在上面概述的解析的一些变化.它可以在自定义Action类中完成,或者按照我的建议进行解析.

哎呀,这个答案几乎是我几天前写的一个克隆:https: //stackoverflow.com/a/33639147/901925

一个类似的2011年问题: 使用argparse来解析形式为"arg = val"的参数

Python argparse dict arg

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

(编辑)

采用以下函数的示例*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'])
Run Code Online (Sandbox Code Playgroud)

所以我有2个位置参数,一个具有单个字符串值,另一个具有列表(由于+nargs).

foo使用以下args属性调用:

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']}
Run Code Online (Sandbox Code Playgroud)

我定义了'位置',但它与'选项'一样有效.位置和选项之间的区别在命名空间中消失.

如果我将命名空间转换为字典,我可以通过或通过foo各种方式传递值.这一切都在我怎么称呼,而不是他们如何出现在或.这些都不是唯一的.*args**kwargsfooargsargumentsargparse

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'}
Run Code Online (Sandbox Code Playgroud)