且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何优雅地解析命令行选项(下)

更新时间:2022-06-23 00:31:38

输出结果:

$ python test_getopt.py -d  -t
[('-d', ''), ('-t', '')]
[]

当然,如果输入的参数少于预期,也不会导致解析失败:

$ python test_getopt.py  -t
[('-t', '')]
[]

但要是给出了预期之外的参数,就会导致模块抛错:

$ python test_getopt.py -d  -t -k
Traceback (most recent call last):
  File "test_getopt.py", line 11, in <module>
    opts, args = getopt.getopt(sys.argv[1:], 'dt')
    ...
    raise GetoptError(_('option -%s not recognized') % opt, opt)
getopt.GetoptError: option -k not recognized

这样的处理逻辑也符合我们使用命令的体验,可以简单地理解为“宁缺毋滥”。

如果短参数相应的字母后带了一个冒号:,则意味着这个参数需要指定一个参数值。getopt会将该参数对应的下一个命令行参数作为参数值(而不论下一个参数是什么形式):

import sys
import getopt


opts, args = getopt.getopt(sys.argv[1:], 'd:t')

print(opts)
print(args)

# $ python test_getopt.py -d  -t
# [('-d', '-t')]
# []

此外,一旦getopt在预期接收到长短选项的位置没有找到以“--”或“-”开头的字符串,就会终止解析过程,剩下的未解析字符串均放在返回元组的第二项中返回。

$ python test_getopt.py -d d_value o --pattern -t
[('-d', 'd_value')]
['o', '--pattern', '-t']

类似地,longopts参数表示需要解析的长参数。

列表中的每一个字符串代表一个长参数:

import sys
import getopt


opts, args = getopt.getopt(sys.argv[1:], '', ["author", "country"])

print(opts)
print(args)

# $ python test_getopt.py --author  --country
# [('--author', ''), ('--country', '')]
# []

要解析带有参数值的长参数,还应在每个长参数后附带一个等于号(=),以标识该参数需要带值:

import sys
import getopt


opts, args = getopt.getopt(sys.argv[1:], '', ["author=", "country"])

print(opts)
print(args)

# $ python test_getopt.py --author justdopython --country
# [('--author', 'justdopython'), ('--country', '')]
# []

所以最终就得到了我们一开始的解析结果:

import sys
import getopt


opts, args = getopt.getopt(sys.argv[1:], 'd:t:', ["author=", "country=", "auto"])

print(opts)
print(args)

# $ python test_getopt.py -d today -t now --author justdopython --country China --auto
# [('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]
# []

解析完成后,我们再从opts中提取相应的值即可。

懒人福音

getopt除了替我们节省了编写命令行参数解析代码的时间和精力,另一方面还可以让你在输入命令行参数时少打几个字母——当然,严谨来讲,我们并不建议此类行为。慎用,慎用!

getopt对长参数的解析支持前缀匹配,只要输入的参数能够与某个指定参数唯一匹配,同样能够完成预期解析。

$ python test_getopt.py -d today -t now --auth justdopython --coun China --auto
[('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]
[]

可以看到,authorcountry两个参数我们都只输入了一部分,但是getopt依然进行了正确的解析。

总结

本文讲解了使用Python解析命令行参数的两种方式,一种是略显笨重的手动解析,即自己编写程序自定义解析;另一种则是调用现成、且更加健壮的getopt模块来完成解析。

从此以后,我们终于可以摆脱繁琐的配置文件,用一种优雅简洁的方式来修改程序的行为了。