[英]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.