用docopt替换sys.argv

时间:2016-01-22 21:28:52

标签: python string replace sys docopt

我正在努力合并一些字符串替换,目前使用sys.argv[i]将参数传递给我的脚本。我想用docopt替换sys,但到目前为止我发现文档还不太清楚。

我的代码目前的工作方式是

filename.py -param_to_replace new_param_value

(我还可以包含多个params来替换)

然后由

处理
if len(sys.argv) > 1:
    for i in range((len(sys.argv)-1) / 2):
        params[sys.argv[1+2*i].split('-')[1]] = float(sys.argv[1+2*i+1])

其中params是一组已定义参数的名称。

我认为我应该能够使用docopt,但到目前为止我所拥有的更像是

"""Docopt test
Usage:
  filename.py --param_name1 <val> --param_name2 <val>

  filename -h | --help
  filename --version

Options:
  -h --help     Show this screen.
  --param_name1 Change some param we call param_name1, all other params changed in similar way


"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='filename 1.0')
    print(arguments)

但这并未传递任何内容,似乎是官方文档中提供的详细信息的结尾。有更熟悉docopt的人是否知道如何更有效地传递命令行参数?或者我应该在此之后用“arguments”替换sys.argv吗?

谢谢!

4 个答案:

答案 0 :(得分:0)

而不是使用docopt(无论如何都很棒),如果您只想构建一个-paramvalue的字典,因为docopt会返回,您可以使用字典来完成理解(我想以比你现在所做的更容易理解的方式):

if __name__ == '__main__':
    if len(sys.argv) > 1:
        args = sys.argv[1:]
        assert len(args) % 2 == 0
        arguments = {args[i][1:]: args[i+1] for i in range(0, len(args), 2)}
        print(arguments)

然后测试一下:

In [12]: runfile(
             'test.py', wdir='/home/mgc',
              args='-param_to_replace1 new_value1 -param_to_replace2 new_param_valu2')

{'param_to_replace2': 'new_param_valu2', 'param_to_replace1': 'new_value1'}

答案 1 :(得分:0)

我刚刚意识到__doc__正在做什么(请参阅我的评论)。

加载模块时,会将初始三重引号字符串分配给其__doc__变量。通常这是各种“帮助”包可以使用的文档。函数和类也有__doc__。对于docopt使用,它应该模拟命令行解析器的help显示。

arguments = docopt(__doc__, version='filename 1.0')

行将此__doc__字符串传递给docopt函数(或类)。这推断出你想接受的参数,解析sys.argv,并返回一个字典arguments

在您的示例中,使用行是:

filename.py --param_name1 <val> --param_name2 <val>

如果您使用

调用脚本,我希望如此
filename.py --param_name1 foo --param_name2 bar

arguments将是一个类似于:

的字典
{'param_name1':'foo', 'param_name2':'bar'}

arguments['param_name1']应该返回'foo'

您当前的代码显然试图解析像

这样的输入
filename.py -foo 2.323 -xxx 1.23

并执行

params['foo'] = 2.323
params['xxx'] = 1.23

我希望docopt版本会在输入时产生错误,但我不知道它处理错误的细节。

Better solution than if __name__ == '__main__' twice in Python script是使用python docopt的较长示例。

argparse版本

这是一个argparse脚本,我认为它与你的sys.argv解析一样。它在argparse字典中定义了一组基于params参数的条目,并且应该返回一个兼容的字典。

import argparse

params = {'foo':None, 'bar':None, 'test':0}

parser = argparse.ArgumentParser()
for key in params:
    name = '--'+key
    default = params[key]
    if default is None:
        parser.add_argument(name)
    else:
        # could be more elaborate on setting type
        parser.add_argument(name, default=default, type=float)

parser.print_help()
print(params)
print(vars(parser.parse_args([]))) # no arguments, should == params
args = parser.parse_args()  # test the sys.argv
print(args)   # namespace
print(vars(args))  # dictionary equivalent
制造

1033:~/mypy$ python stack34956253.py --foo 124 --test 323.3
usage: stack34956253.py [-h] [--test TEST] [--foo FOO] [--bar BAR]

optional arguments:
  -h, --help   show this help message and exit
  --test TEST
  --foo FOO
  --bar BAR
{'test': 0, 'foo': None, 'bar': None}
{'test': 0, 'foo': None, 'bar': None}
Namespace(bar=None, foo='124', test=323.3)
{'test': 323.3, 'foo': '124', 'bar': None}

这可能会以同样的方式运作:

argparse_help = parser.format_help()
arguments = docopt(argparse_help, version='filename 1.0')

答案 2 :(得分:0)

看起来你的docopt语法有问题。对我来说,使用web docopt tool来计算docopt语法是有帮助的。这个设置可以很容易地快速迭代语法,看看它是否会产生一个对我的程序有用的结构。

我把你的语法放在here中,带有--param_name1 foo --param_name2 bar参数并得到了这个结果:

{
  "--param_name1": "foo", 
  "--param_name2": true, 
  "<val>": "bar"
}

在第一部分中,您指定了:Usage: filename.py --param_name1 <val> --param_name2 <val>。请注意,您在2个不同的位置使用了<val>,这意味着只填充了第2个值。在第二部分中,您再次指定了Options: --param_name1,这是多余的,因为您已在使用部分中指定了相同的--param_name1。参数应该在一个但不是两个部分中。

Here是一种简化的语法:

Usage:
  filename --old=<old> --new=<new>

使用--old=foo --new=bar解析的结果是:

{
  "--new": "bar", 
  "--old": "foo"
}

或者完全删除开关名称,只使用位置参数。 This可以更轻松地预测您要替换的多个参数。

Usage:
  filename <new> <old>...

使用bar foo baz个参数,这是解析后的结构:

{
  "<new>": "bar", 
  "<old>": [
    "foo", 
    "baz"
  ]
}

我只是blogged关于我有多喜欢docopt,所以我希望你能克服最初的理解障碍。

答案 3 :(得分:0)

所以我想我会回到这个,因为我意识到我从未关闭主题并发布答案。传递参数的正确方法如下:

"""Usage: filename.py [--arg1=N] [--arg2=N] 

Options:
    --arg1=N passes arg1
    --arg2=N passes arg2
"""

 from docopt import docopt 
 arguments = docopt(__doc__,version='')
 print arguments[--arg1] #This is to print any argument or pass it through

似乎使用中存在一些问题,这在代码中已经清除。