用 docopt 替换 sys.argv
Replacing sys.argv with docopt
我正在努力合并一些字符串替换,目前使用 sys.argv[i]
将参数传递到我的脚本。我想用 docopt 替换 sys,但到目前为止我发现文档相对不清楚。
我的代码目前的工作方式是
filename.py -param_to_replace new_param_value
(我也可以包含多个参数来替换)
然后由
处理
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 吗?
谢谢!
而不是使用 docopt
(无论如何都很棒),如果你只是想构建一个 -param
: value
的字典,因为 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'}
我刚刚意识到 __doc__
在做什么(请参阅我的评论)。
加载模块时,初始的三引号字符串被分配给它的 __doc__
变量。通常这是各种 'help' 软件包可以使用的文档。函数和 classes 也有 __doc__
。对于 docopt
使用,它应该模拟命令行解析器的 help
显示。
arguments = docopt(__doc__, version='filename 1.0')
行将此 __doc__
字符串传递给 docopt
函数(或 class)。这会推断出您想要接受的参数,解析 sys.argv
,并且 return 是一个字典,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']
应该return'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
解析。它在 params
字典中定义了一组基于 argparse
参数的条目,并且应该 return 一个兼容的字典。
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')
您的 docopt 语法似乎有问题。对我来说,它有助于使用 web docopt tool 计算出 docopt 语法。该设置使得快速迭代语法并查看它是否会生成对我的程序有用的结构变得容易。
我将你的语法和参数 --param_name1 foo --param_name2 bar
放在 here 中,得到了这个结果:
{
"--param_name1": "foo",
"--param_name2": true,
"<val>": "bar"
}
在第一部分中,您指定了:Usage: filename.py --param_name1 <val> --param_name2 <val>
。请注意,您在 2 个不同的位置使用了 <val>
,这意味着仅填充了第二个值。在第二部分,您再次指定: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,所以我希望你能克服最初的理解障碍。
所以我想我会 return 对此,因为我意识到我从未关闭该主题并且 post 一个答案。传递参数的正确方法如下:
"""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
似乎只是使用上出现了一些问题,已在此处的代码中解决。
我正在努力合并一些字符串替换,目前使用 sys.argv[i]
将参数传递到我的脚本。我想用 docopt 替换 sys,但到目前为止我发现文档相对不清楚。
我的代码目前的工作方式是
filename.py -param_to_replace new_param_value
(我也可以包含多个参数来替换)
然后由
处理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 吗?
谢谢!
而不是使用 docopt
(无论如何都很棒),如果你只是想构建一个 -param
: value
的字典,因为 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'}
我刚刚意识到 __doc__
在做什么(请参阅我的评论)。
加载模块时,初始的三引号字符串被分配给它的 __doc__
变量。通常这是各种 'help' 软件包可以使用的文档。函数和 classes 也有 __doc__
。对于 docopt
使用,它应该模拟命令行解析器的 help
显示。
arguments = docopt(__doc__, version='filename 1.0')
行将此 __doc__
字符串传递给 docopt
函数(或 class)。这会推断出您想要接受的参数,解析 sys.argv
,并且 return 是一个字典,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']
应该return'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
解析。它在 params
字典中定义了一组基于 argparse
参数的条目,并且应该 return 一个兼容的字典。
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')
您的 docopt 语法似乎有问题。对我来说,它有助于使用 web docopt tool 计算出 docopt 语法。该设置使得快速迭代语法并查看它是否会生成对我的程序有用的结构变得容易。
我将你的语法和参数 --param_name1 foo --param_name2 bar
放在 here 中,得到了这个结果:
{
"--param_name1": "foo",
"--param_name2": true,
"<val>": "bar"
}
在第一部分中,您指定了:Usage: filename.py --param_name1 <val> --param_name2 <val>
。请注意,您在 2 个不同的位置使用了 <val>
,这意味着仅填充了第二个值。在第二部分,您再次指定: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,所以我希望你能克服最初的理解障碍。
所以我想我会 return 对此,因为我意识到我从未关闭该主题并且 post 一个答案。传递参数的正确方法如下:
"""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
似乎只是使用上出现了一些问题,已在此处的代码中解决。