简体   繁体   English

整齐地将位置参数作为args和可选参数传递为从argparse到函数的kwargs

[英]Neatly pass positional arguments as args and optional arguments as kwargs from argparse to a function

I would like to write a Python script that takes some necessary positional and some optional command-line arguments via argparse : 我想编写一个Python脚本,通过argparse获取一些必要的位置和一些可选的命令行参数:

  • Let's call the positional args a , b , c , and the optional arguments x , y , z . 让我们调用位置args abc和可选参数xyz
  • In my Python script, I would like to pass these args on to a function; 在我的Python脚本中,我想将这些args传递给一个函数; specifically, I want a , b , c to be passed as *args , and x , y , z to be passed as **kwargs , the latter retaining their names. 具体来说,我希望abc作为*args传递, xyz作为**kwargs传递,后者保留其名称。
  • I would like to do this many times with different functions and different numbers of positional and optional arguments. 我想用不同的函数和不同数量的位置和可选参数做很多次。 Is there a neat, flexible, and/or pythonic way to do this? 是否有一种整洁,灵活和/或pythonic的方式来做到这一点?

Here is some example code: 这是一些示例代码:

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)

The Namespace you get back from parse_args will have attributes corresponding to each of your arguments. parse_args返回的Namespace将具有与每个参数对应的属性。 There will be no distinction between the positional arguments and the optionals, eg: 位置参数和选项之间没有区别,例如:

args
Namespace(a='1',b='one',x='foo', y=...)

Which, as is well documented, can be accessed as: 根据文档记录,可以访问以下内容:

args.a
args.x
etc.

The Namespace can also be turned into a dictionary: Namespace也可以变成字典:

vars(args)
{'a'='1', 'b'='one', etc.}

You can pass the dictionary to a function as **kwargs . 您可以将字典作为**kwargs传递给函数。 That's standard Python argument practice. 这是标准的Python参数练习。

If you want to pass some arguments as *args you'll have to split those off the Namespace or dictionary yourself. 如果你想将一些参数作为*args传递,你必须自己将它们从Namespace或字典中分离出来。 Nothing in argparse will do that for you. argparse任何内容都不会为您做到这一点。

You could write a function like (not tested): 你可以写一个像(未测试)的函数:

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

Or more compactly, put the pop in a list comprehension: 或者更紧凑,将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}

Further idea using custom Action class 使用自定义Action类的进一步想法

The parser determines whether an argument is an optional vs. positional by its option_strings attribute. parser通过其option_strings属性确定参数是optional positional的。 add_argument returns an Action subclass, which will have attributes like: add_argument返回一个Action子类,它将具有以下属性:

MyAction(option_strings=[], dest='baz', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)

This is a positional because option_strings is an empty list. 这是一个positional因为option_strings是一个空列表。

MyAction(option_strings=['-m', '--mew'], dest='mew', nargs=None,...)

is an optional because that list is not empty. optional因为该列表不为空。

The parser matches input strings with the option_strings and nargs , and then passes values to the __call__ method of the matching Action . 解析器使用option_stringsnargs匹配输入字符串,然后将值传递给匹配Action__call__方法。 This method is defined like: 此方法定义如下:

def __call__(self, parser, namespace, values, option_string=None):
    setattr(namespace, self.dest, values)

This is the default store action. 这是默认的store操作。 The values are put in the Namespace as the dest attribute. 这些值作为dest属性放在Namespace中。

The option_string parameter is the string that triggered this call, something like '-m' or '--mew', or None for a positional . option_string参数是触发此调用的字符串,类似于'-m'或'--mew',或者是positional None The defined action types don't make use of this, but a user-defined Action class could do something. 定义的操作类型不使用它,但是用户定义的Action类可以执行某些操作。

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])

Or you could do something special with positionals , eg 或者你可以做一些特殊的positionals ,例如

       if option_string is None:
           # append values to a `star_args` attribute
           # rather than self.dest

With an action like this positionals could be accessed after parsing as: 通过这样的操作,可以在解析后访问positionals

args.star_args

The parser does maintain a list attribute like this. 解析器确实维护这样的列表属性。 The extras that parse_known_args returns are stored temporarily in the Namespace in the '_UNRECOGNIZED_ARGS_ATTR' attribute. parse_known_args返回的extras存储在“_UNRECOGNIZED_ARGS_ATTR”属性的Namespace中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM