如何在使用Python的optparse模块时遵循PEP 257文档字符串?
根据PEP 257的规定,命令行脚本的文档字符串应该是它的使用说明。
一个脚本(独立程序)的文档字符串应该可以作为它的“使用”信息,当脚本被错误地调用或者缺少参数时(或者用“-h”选项请求帮助时)会打印出来。这样的文档字符串应该描述脚本的功能和命令行的语法、环境变量和文件。使用说明可以相当详细(可能有好几屏内容),应该足够让新用户正确使用这个命令,同时也能为高级用户提供所有选项和参数的快速参考。
所以我的文档字符串可能看起来像这样:
<tool name> <copyright info> Usage: <prog name> [options] [args] some text explaining the usage... Options: -h, --help show this help message and exit ...
现在我想使用optparse模块。optparse会生成“选项”部分和一个解释命令行语法的“使用”说明:
from optparse import OptionParser
if __name__ == "__main__":
parser = OptionParser()
(options, args) = parser.parse_args()
所以用“-h”标志调用脚本时会打印:
Usage: script.py [options] Options: -h, --help show this help message and exit
这可以修改成如下:
parser = OptionParser(usage="Usage: %prog [options] [args]",
description="some text explaining the usage...")
结果是
Usage: script.py [options] [args] some text explaining the usage... Options: -h, --help show this help message and exit
但是我该如何在这里使用文档字符串呢?把文档字符串作为使用说明有两个问题。
- 如果文档字符串不以“Usage: ”开头,optparse会在前面加上“Usage: ”
- 文档字符串中必须使用占位符'%prog'
结果
根据回答来看,似乎没有办法重用optparse模块所期望的文档字符串。所以剩下的选择是手动解析文档字符串并构建OptionParser。(所以我会接受S.Loot的回答)
“Usage: ”部分是由IndentedHelpFormatter引入的,可以通过OptionParser.__init__()中的formatter参数进行替换。
3 个回答
我觉得我们在看这个PEP的建议时要保持理智。我认为把模块的__doc__
设置为一个简短的描述,总结一下长篇的用法,这样是可以的。不过如果你是个追求完美的人:
'''<tool name>
The full description and usage can be generated by optparse module.
Description: ...
'''
...
# Generate usage and options using optparse.
usage, options = ...
# Modify the docstring on the fly.
docstring = __doc__.split('\n\n')
docstring[1:2] = [__license__, usage, options]
__doc__ = '\n\n'.join(docstring)
我写了一个模块 docopt
,正好可以满足你的需求——在文档字符串中写使用说明,并保持代码的简洁性(DRY)。
这个模块还可以让你完全避免写那些繁琐的 OptionParser
代码,因为 docopt
会根据使用说明自动生成解析器。
你可以去看看:http://github.com/docopt/docopt
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship [<name>] move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored|--drifting]
naval_fate.py -h | --help
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
选择一:复制粘贴。这种方法虽然不够简洁,但可以用。
选择二:解析你自己的文档字符串,去掉描述段落。描述段落总是第二段,所以你可以用'\n\n'来分割。
usage, description= __doc__.split('\n\n')[:2]
因为optparse
会自动生成使用说明,所以你可能不想给它提供使用说明的句子。你自己写的使用说明可能会有错误。如果你坚持要给optparse
提供一个使用说明字符串,我就不告诉你怎么去掉上面生成的usage
字符串前面的"Usage: "
部分,留给你自己去研究。