自定义argparse格式化器导致usage文本显示对象实例的问题分析与咨询
自定义argparse格式化器导致usage文本显示对象实例的问题分析与解决
嗨,我帮你排查了这个问题,其实就是自定义格式化器的初始化方法里一个小参数传错了,导致argparse把格式化器实例本身当成程序名(prog)来显示,所以才会出现那个奇怪的对象字符串。
问题根源
看你的MyFormatter类的__init__方法,调用父类构造函数的时候,第一个参数错误地传成了self:
super().__init__(self, indent_increment=indent_increment, max_help_position=max_help_position, width=width)
但实际上ArgumentDefaultsHelpFormatter的构造函数第一个参数应该是prog(也就是你的脚本名,比如test.py)。你把当前的格式化器实例传进去后,argparse在生成usage文本时就用了这个对象的字符串表示,也就是你看到的<__main__.MyFormatter object at 0x7f30cc163c70>。
修复方法
只需要把super().__init__的第一个参数从self改成prog就行,修正后的完整MyFormatter类代码如下:
import argparse class MyFormatter(argparse.ArgumentDefaultsHelpFormatter): def __init__(self, prog, indent_increment=2, max_help_position=30, width=None): # 替换第一个参数为prog,而非self super().__init__(prog, indent_increment=indent_increment, max_help_position=max_help_position, width=width) def _split_lines(self, text, width): """ If the text starts with 'S|', remove the prefix, split the text into lines at the new line '\n' and maintain spaces. Otherwise, uses the default splitting behavior of ArgumentDefaultsHelpFormatter. """ if text.startswith('S|'): text = text[2:].strip().splitlines() import textwrap out = [] for line in text: out.extend(textwrap.wrap(line, width)) return out return argparse.ArgumentDefaultsHelpFormatter._split_lines(self, text, width)
额外小优化
另外,你不用在每个子parser(parser_list、parser_add、parser_remove)里都重复指定formatter_class=MyFormatter,只要在主parser里设置了,子parser会自动继承这个格式化器配置,这样代码会更简洁。
现在你再运行python test.py -h,usage文本就会正常显示成usage: test.py [-h] {list,add,remove} ...啦~
备注:内容来源于stack exchange,提问作者stefanos
相关产品推荐
相关产品推荐

