简体   繁体   English

Python:如何在从命令行调用时启用kwargs? (也许与argparse)

[英]Python: How can I enable use of kwargs when calling from command line? (perhaps with argparse)

suppose I have the module myscript.py; 假设我有模块myscript.py; This module is production code, and is called often as %dir%>python myscript.py foo bar . 此模块是生产代码,通常称为%dir%>python myscript.py foo bar

I want to extend it to take keyword arguments. 我想扩展它以获取关键字参数。 I know that I can take these arguments using the script below, but unfortunately one would have to call it using 我知道我可以使用下面的脚本来获取这些参数,但不幸的是,我们必须使用它来调用它

%dir%>python myscript.py main(foo, bar) . %dir%>python myscript.py main(foo, bar)

I know that I can use the argparse module, but I'm not sure how to do it. 我知道我可以使用argparse模块,但我不知道该怎么做。

import sys

def main(foo,bar,**kwargs):
    print 'Called myscript with:'
        print 'foo = %s' % foo
        print 'bar = %s' % bar
        if kwargs:
            for k in kwargs.keys():
                print 'keyword argument : %s' % k + ' = ' + '%s' % kwargs[k]   

if __name__=="__main__":
    exec(''.join(sys.argv[1:]))

@Moon beat me to it with a similar solution, but I'd suggest doing the parsing beforehand and passing in actual kwargs : @Moon用类似的解决方案打败了我,但我建议事先进行解析并传入实际的kwargs

import sys

def main(foo, bar, **kwargs):
    print('Called myscript with:')
    print('foo = {}'.format(foo))
    print('bar = {}'.format(bar))
    for k, v in kwargs.items():
        print('keyword argument: {} = {}'.format(k, v))

if __name__=='__main__':
    main(sys.argv[1], # foo
         sys.argv[2], # bar
         **dict(arg.split('=') for arg in sys.argv[3:])) # kwargs

# Example use:
# $ python myscript.py foo bar hello=world 'with spaces'='a value'
# Called myscript with:
# foo = foo
# bar = bar
# keyword argument: hello = world
# keyword argument: with spaces = a value

First, you won't be passing an arbitrary Python expression as an argument. 首先,您不会将任意Python表达式作为参数传递。 It's brittle and unsafe. 它很脆弱且不安全。

To set up the argument parser, you define the arguments you want, then parse them to produce a Namespace object that contains the information specified by the command line call. 要设置参数解析器,可以定义所需的参数,然后解析它们以生成包含命令行调用指定的信息的Namespace对象。

import argparse
p = argparse.ArgumentParser()
p.add_argument('foo')
p.add_argument('bar')
p.add_argument('--add-feature-a', dest='a', action='store_true', default=False)

In your __main__ block, you'll parse the arguments, then pass a dictionary produced from the Namespace to main . __main__块中,您将解析参数,然后将从Namespace生成的字典传递给main

if __name__ == '__main__':
    args = p.parse_args()
    main(**vars(args))

Then you'll call your script with a line like 然后你会用一行代码调用你的脚本

# foo = "3", bar = "6", a = True
python myscript.py 3 6 --add-feature-a

or 要么

# foo = "moo", bar="7.7", a = False
python myscript.py moo 7.7

There's a lot more you can do with argparse , but this is a simple example for getting the value it produces into main . 你可以用argparse做更多的事情,但这是一个简单的例子,可以将它产生的值变为main

If you want to pass in keyword arguments as you would in the main function, key=value , you can do it like so: 如果你想像在main函数key=value那样传递关键字参数,你可以这样做:

import sys

def main(foo, bar, *args):
    print "Called my script with"

    print "foo = %s" % foo
    print "bar = %s" % bar

    for arg in args:
        k = arg.split("=")[0]
        v = arg.split("=")[1]

        print "Keyword argument: %s = %s" % (k, v)


if __name__ == "__main__":
    if len(sys.argv) < 3:
        raise SyntaxError("Insufficient arguments.")
    if len(sys.argv) != 3:
        # If there are keyword arguments
        main(sys.argv[1], sys.argv[2], *sys.argv[3:])
    else:
        # If there are no keyword arguments
        main(sys.argv[1], sys.argv[2])

Some examples: 一些例子:

$> python my_file.py a b x=4
Called my script with
foo = a
bar = b
Keyword argument: x = 4
$> python my_file.py foo bar key=value
Called my script with
foo = foo
bar = bar
Keyword argument: key = value

However, this assumes that the key and value do not have any whitespace between them, key = value will not work. 但是,这假设键和值之间没有任何空格, key = value将不起作用。

If you are looking for --argument kinds of keyword arguments, you should use argparse . 如果您正在寻找--argument种类的关键字参数,您应该使用argparse

in two lines of code I can get args and kwargs that I can manipulate like standard args and kwargs: 在两行代码中,我可以获得args和kwargs,我可以像标准的args和kwargs一样操作:

import sys


if __name__=='__main__':
  argv=argv[1:] 
  kwargs={kw[0]:kw[1] for kw in [ar.split('=') for ar in argv if ar.find('=')>0]}
  args=[arg for arg in argv if arg.find('=')<0]

  #and you can the use args and kwargs as so:
  if 'reset' in args:
    do_some_functions_with_reset()
  a_device_var=kwargs.get('device',False):
  #or whatever you want to do with args and kwargs

and the result is : 结果是:

$python test.py reset device=foo format=1 bar
->args=['reset','bar']
->kwargs={'device':'foo','format':'1'}

With a bit of introspection, it's possible to set up ArgumentParser from a function's signature, thus mapping command-line parameters directly to function arguments: 通过一些内省,可以从函数的签名中设置ArgumentParser ,从而将命令行参数直接映射到函数参数:

import argparse
import inspect

def myfun(mode, count=1, frobify=False, *files):
    print('Doing %s %d times on %s (%sfrobifying)' % (
        mode, count, files, '' if frobify else 'not '
    ))

def funopt(fun, argv=None):
    parser = argparse.ArgumentParser()

    if hasattr(inspect, 'getfullargspec'):
        spec = inspect.getfullargspec(fun)
    else:
        spec = inspect.getargspec(fun)

    num_defaults = len(spec.defaults) if spec.defaults is not None else 0
    for i in range(len(spec.args)):
        if i < len(spec.args) - num_defaults:
            parser.add_argument(spec.args[i])
        elif spec.defaults[i - len(spec.args)] is False:
            parser.add_argument('--' + spec.args[i], 
                                default=False, action='store_true')
        else:
            default = spec.defaults[i - len(spec.args)]
            parser.add_argument('--' + spec.args[i],
                                default=default,
                                type=type(default))
    if spec.varargs is not None:
            parser.add_argument(spec.varargs,
                                nargs='*')

    kwargs = vars(parser.parse_args(argv))
    args = []
    for arg in spec.args:
        args += [kwargs[arg]]
    if spec.varargs is not None:
        args += kwargs[spec.varargs]

    fun(*args)


funopt(myfun)

The result: 结果:

$ python test.py               
usage: test.py [-h] [--count COUNT] [--frobify] mode [files [files ...]]
test.py: error: too few arguments

$ python test.py myaction a b c
Doing myaction 1 times on ('a', 'b', 'c') (not frobifying)

$ python test.py --frobify --count=5 myaction a b c 
Doing myaction 5 times on ('a', 'b', 'c') (frobifying)

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

相关问题 有没有办法在从命令行调用Python脚本时实现** kwargs行为 - Is there a way to implement **kwargs behavior when calling a Python script from the command line Python:使用 argparse 从命令行调用 function - Python: Calling function from command line using argparse 如何使用argparse在Python中抓取命令行arguments? - How to use argparse to grab command line arguments in Python? 如何使用 argparse 在命令行上输入不同类型的 arguments? - How can I use argparse to input different type arguments on the command line? python argh / argparse:如何将列表作为命令行参数传递? - python argh/argparse: How can I pass a list as a command-line argument? 如何在Python的argparse中使用命令行参数-h? - How can I have a command-line argument -h with Python's argparse? 当Python argparse中存在命名冲突时,如何从命令行获取2个不同对象的参数 - How to get arguments for 2 different objects from the command line when there is a naming conflict in Python argparse python + argparse - 如何从命令行获取可选参数的顺序 - python + argparse - how to get order of optional arguments from command line Python argparse 如何从命令行传递 False? - Python argparse how to pass False from the command line? 我如何使用python从命令行部署代理 - how can i use python to deploy proxies from the command line
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM