I would like to make my python script run from the command line when supplies with some arguments. However, one of the arguments should be a list of options specific to one segment of the script. Would string parsing be the only way to do this by actually constructing the list after the "command line list" string is split from commas? If so, how would you go about that?
我想让我的python脚本从命令行运行,当提供一些参数时。但是,其中一个参数应该是特定于脚本的某个部分的选项列表。在“命令行列表”字符串从逗号分隔开之后,字符串解析是实现此目的的惟一方法吗?如果是的话,你会怎么做?
Example: -details=['name', 'title', 'address']
例子:细节=['名称','标题','地址']
4 个解决方案
#1
28
Program:
计划:
import sys, ast, getopt, types
def main(argv):
arg_dict={}
switches={'li':list,'di':dict,'tu':tuple}
singles=''.join([x[0]+':' for x in switches])
long_form=[x+'=' for x in switches]
d={x[0]+':':'--'+x for x in switches}
try:
opts, args = getopt.getopt(argv, singles, long_form)
except getopt.GetoptError:
print "bad arg"
sys.exit(2)
for opt, arg in opts:
if opt[1]+':' in d: o=d[opt[1]+':'][2:]
elif opt in d.values(): o=opt[2:]
else: o =''
print opt, arg,o
if o and arg:
arg_dict[o]=ast.literal_eval(arg)
if not o or not isinstance(arg_dict[o], switches[o]):
print opt, arg, " Error: bad arg"
sys.exit(2)
for e in arg_dict:
print e, arg_dict[e], type(arg_dict[e])
if __name__ == '__main__':
main(sys.argv[1:])
Command line:
命令行:
python py.py --l='[1,2,3,[1,2,3]]' -d "{1:'one',2:'two',3:'three'}" --tu='(1,2,3)'
Output:
输出:
args: ['--l=[1,2,3,[1,2,3]]', '-d', "{1:'one',2:'two',3:'three'}", '--tu=(1,2,3)']
tu (1, 2, 3) <type 'tuple'>
di {1: 'one', 2: 'two', 3: 'three'} <type 'dict'>
li [1, 2, 3, [1, 2, 3]] <type 'list'>
This code snippet will take short or long command switches like -l
or --li=
and parse the text after the switch into a Python data structure like a list, tuple or a dict. The parsed data structure ends up in a dictionary with the long-form switch key.
该代码片段将使用短或长命令开关,如-l或-li=并在切换到Python数据结构(如列表、tuple或dict)后解析文本。
Using ast.literal_eval is relatively safe. It can only parse python data definitions.
使用ast.literal_eval是相对安全的。它只能解析python数据定义。
#2
24
argparse is nice for this, it's in the standard library as of 2.7 and 3.2 but otherwise a pip install
away.
argparse是不错的,它在标准库中是2.7和3.2,但是其他的是pip安装。
Your main concern of specifying a variable-length list can be addressed by making the list interpreted as a single argument in the shell by using quotes (could depend on your shell I suppose):
通过使用引号将列表解释为shell中的单个参数(可以依赖于您的shell),可以解决指定变量长度列表的主要问题:
% python prog.py 'name title address' spam
where prog.py contains
食物的地方。py包含
import sys
my_list = sys.argv[1].split()
# my_list is ['name', 'title', 'address']
if 'name' in my_list:
do_something()
or similar. Use an argument with split to delimit your list:
或类似的。用分裂的论点来划定你的列表:
% python prog.py "you're a foo, lift the bar"
my_list = [x.strip() for x in sys.argv[1].split(',')]
# my_list is ["you're a foo", "lift the bar"]
But please use argparse instead; especially if you want to use use -c
style flags.
但请用argparse代替;特别是如果您想使用-c风格的标志。
One way to interpret your question is:
一种解释你的问题的方法是:
"I'm already using argparse, since that's the sensible way to interpret command line arguments in Python. How do I specify that some options are within a specific category?"
我已经在使用argparse,因为这是解释Python中命令行参数的合理方法。如何指定某些选项属于特定类别?
In your question you've shown an example of something the shells I use of would choke on;
在你的问题中,你展示了一个例子,我用的贝壳会被卡住;
% python prog.py -v -details=['name', 'title', 'address'] --quickly -t 4
wouldn't make it to python to be parsed because they'd use spaces to separate arguments and might use [ and ] as shell syntax.
不能将其解析为python,因为它们将使用空格分隔参数,并可能使用[和]作为shell语法。
I suggest the following instead
我建议如下所示。
% python prog.py -v --details name title address --quickly -t 4
where a prog.py file of
食物的地方。py文件
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-v', action='store_true')
parser.add_argument('--details', nargs='*')
parser.add_argument('--quickly', action='store_true')
parser.add_argument('-t')
args = parser.parse_args()
#args is Namespace(details=['asdf', 'a', 'a'], quickly=False, t='4', v=True)
details = args.details
#details is ['asdf', 'a', 'a']
Now, as per your question, you didn't have to do the string parsing yourself.
现在,根据你的问题,你不必自己做字符串解析。
#3
3
Yes, argparse is your best bet, and if you want to provide a list of values to one of your named arguments, it looks like this (the nargs
parameter is the key to this):
是的,argparse是您最好的选择,如果您想为您的一个命名参数提供一个值列表,它看起来是这样的(nargs参数是这个的关键):
>>> import argparse
>>> arg_parser = argparse.ArgumentParser()
>>> arg_parser.add_argument('--details',
nargs='*',
type=str,
default=[],
help='a list of the details')
# your args on the command line like this example
>>> the_args = arg_parser.parse_args("--details 'name' 'title' 'address'".split())
>>> print the_args.details
["'name'", "'title'", "'address'"])
#4
0
I really like the-wolf's approach using variable length collections as explicit string arguments.
我非常喜欢使用可变长度集合作为显式字符串参数的狼的方法。
In my opinion, nargs='*'
has noteworthy drawbacks: when attempting to collect strings as positional arguments (at least one string must be present), or if you are trying to use subparsers, you will find that nargs='*'
and nargs='+'
use greedy completion, and they don't seem to stop consuming for any good reasons. Even if syntax for an optional argument or a number comes up, the string() type will keep consuming. (This gets harder to anticipate with subparsers).
在我看来,娜戈=‘*’有值得注意的缺点:当试图收集字符串作为位置参数(必须提供至少一个字符串),或者如果你想使用subparsers,你会发现娜戈=‘*’和娜戈= ' + '使用贪婪的完成,他们似乎不为任何理由停止消费。即使一个可选参数或一个数字的语法出现,string()类型也会继续使用。(这越来越难预料到有子解析器)。
Best case, arguments placed after (positional and optional) are being ignored, and worse, you are likely passing corrupt data types to the argparse array.
最好的情况是,在(位置和可选)之后放置的参数被忽略,更糟糕的是,您可能会将损坏的数据类型传递给argparse数组。
We should be able to define a custom ActionType that is looking for a quoted string. If it finds one, then we adapt the-wolf's examples (nearly verbatim it seems).
我们应该能够定义一个自定义的ActionType,它正在寻找引用的字符串。如果它找到了一个,那么我们就采用了狼的例子(看起来几乎是一字不差)。
This keep things clean in argparse and makes general use of variable collections much less bitchy.
这使得在argparse中保持干净,并使变量集合的通用使用更少。
#1
28
Program:
计划:
import sys, ast, getopt, types
def main(argv):
arg_dict={}
switches={'li':list,'di':dict,'tu':tuple}
singles=''.join([x[0]+':' for x in switches])
long_form=[x+'=' for x in switches]
d={x[0]+':':'--'+x for x in switches}
try:
opts, args = getopt.getopt(argv, singles, long_form)
except getopt.GetoptError:
print "bad arg"
sys.exit(2)
for opt, arg in opts:
if opt[1]+':' in d: o=d[opt[1]+':'][2:]
elif opt in d.values(): o=opt[2:]
else: o =''
print opt, arg,o
if o and arg:
arg_dict[o]=ast.literal_eval(arg)
if not o or not isinstance(arg_dict[o], switches[o]):
print opt, arg, " Error: bad arg"
sys.exit(2)
for e in arg_dict:
print e, arg_dict[e], type(arg_dict[e])
if __name__ == '__main__':
main(sys.argv[1:])
Command line:
命令行:
python py.py --l='[1,2,3,[1,2,3]]' -d "{1:'one',2:'two',3:'three'}" --tu='(1,2,3)'
Output:
输出:
args: ['--l=[1,2,3,[1,2,3]]', '-d', "{1:'one',2:'two',3:'three'}", '--tu=(1,2,3)']
tu (1, 2, 3) <type 'tuple'>
di {1: 'one', 2: 'two', 3: 'three'} <type 'dict'>
li [1, 2, 3, [1, 2, 3]] <type 'list'>
This code snippet will take short or long command switches like -l
or --li=
and parse the text after the switch into a Python data structure like a list, tuple or a dict. The parsed data structure ends up in a dictionary with the long-form switch key.
该代码片段将使用短或长命令开关,如-l或-li=并在切换到Python数据结构(如列表、tuple或dict)后解析文本。
Using ast.literal_eval is relatively safe. It can only parse python data definitions.
使用ast.literal_eval是相对安全的。它只能解析python数据定义。
#2
24
argparse is nice for this, it's in the standard library as of 2.7 and 3.2 but otherwise a pip install
away.
argparse是不错的,它在标准库中是2.7和3.2,但是其他的是pip安装。
Your main concern of specifying a variable-length list can be addressed by making the list interpreted as a single argument in the shell by using quotes (could depend on your shell I suppose):
通过使用引号将列表解释为shell中的单个参数(可以依赖于您的shell),可以解决指定变量长度列表的主要问题:
% python prog.py 'name title address' spam
where prog.py contains
食物的地方。py包含
import sys
my_list = sys.argv[1].split()
# my_list is ['name', 'title', 'address']
if 'name' in my_list:
do_something()
or similar. Use an argument with split to delimit your list:
或类似的。用分裂的论点来划定你的列表:
% python prog.py "you're a foo, lift the bar"
my_list = [x.strip() for x in sys.argv[1].split(',')]
# my_list is ["you're a foo", "lift the bar"]
But please use argparse instead; especially if you want to use use -c
style flags.
但请用argparse代替;特别是如果您想使用-c风格的标志。
One way to interpret your question is:
一种解释你的问题的方法是:
"I'm already using argparse, since that's the sensible way to interpret command line arguments in Python. How do I specify that some options are within a specific category?"
我已经在使用argparse,因为这是解释Python中命令行参数的合理方法。如何指定某些选项属于特定类别?
In your question you've shown an example of something the shells I use of would choke on;
在你的问题中,你展示了一个例子,我用的贝壳会被卡住;
% python prog.py -v -details=['name', 'title', 'address'] --quickly -t 4
wouldn't make it to python to be parsed because they'd use spaces to separate arguments and might use [ and ] as shell syntax.
不能将其解析为python,因为它们将使用空格分隔参数,并可能使用[和]作为shell语法。
I suggest the following instead
我建议如下所示。
% python prog.py -v --details name title address --quickly -t 4
where a prog.py file of
食物的地方。py文件
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-v', action='store_true')
parser.add_argument('--details', nargs='*')
parser.add_argument('--quickly', action='store_true')
parser.add_argument('-t')
args = parser.parse_args()
#args is Namespace(details=['asdf', 'a', 'a'], quickly=False, t='4', v=True)
details = args.details
#details is ['asdf', 'a', 'a']
Now, as per your question, you didn't have to do the string parsing yourself.
现在,根据你的问题,你不必自己做字符串解析。
#3
3
Yes, argparse is your best bet, and if you want to provide a list of values to one of your named arguments, it looks like this (the nargs
parameter is the key to this):
是的,argparse是您最好的选择,如果您想为您的一个命名参数提供一个值列表,它看起来是这样的(nargs参数是这个的关键):
>>> import argparse
>>> arg_parser = argparse.ArgumentParser()
>>> arg_parser.add_argument('--details',
nargs='*',
type=str,
default=[],
help='a list of the details')
# your args on the command line like this example
>>> the_args = arg_parser.parse_args("--details 'name' 'title' 'address'".split())
>>> print the_args.details
["'name'", "'title'", "'address'"])
#4
0
I really like the-wolf's approach using variable length collections as explicit string arguments.
我非常喜欢使用可变长度集合作为显式字符串参数的狼的方法。
In my opinion, nargs='*'
has noteworthy drawbacks: when attempting to collect strings as positional arguments (at least one string must be present), or if you are trying to use subparsers, you will find that nargs='*'
and nargs='+'
use greedy completion, and they don't seem to stop consuming for any good reasons. Even if syntax for an optional argument or a number comes up, the string() type will keep consuming. (This gets harder to anticipate with subparsers).
在我看来,娜戈=‘*’有值得注意的缺点:当试图收集字符串作为位置参数(必须提供至少一个字符串),或者如果你想使用subparsers,你会发现娜戈=‘*’和娜戈= ' + '使用贪婪的完成,他们似乎不为任何理由停止消费。即使一个可选参数或一个数字的语法出现,string()类型也会继续使用。(这越来越难预料到有子解析器)。
Best case, arguments placed after (positional and optional) are being ignored, and worse, you are likely passing corrupt data types to the argparse array.
最好的情况是,在(位置和可选)之后放置的参数被忽略,更糟糕的是,您可能会将损坏的数据类型传递给argparse数组。
We should be able to define a custom ActionType that is looking for a quoted string. If it finds one, then we adapt the-wolf's examples (nearly verbatim it seems).
我们应该能够定义一个自定义的ActionType,它正在寻找引用的字符串。如果它找到了一个,那么我们就采用了狼的例子(看起来几乎是一字不差)。
This keep things clean in argparse and makes general use of variable collections much less bitchy.
这使得在argparse中保持干净,并使变量集合的通用使用更少。