PEP8与使用长关键字参数初始化对象

5 投票
2 回答
1616 浏览
提问于 2025-04-18 18:55

我觉得在使用 argparse 模块中的 RawDescriptionHelpFormatter 时,没有简单的方法可以做到这一点,而不违反 PEP8 规范或者让命名空间变得杂乱。

这里是最明显的格式化方法:

parser = argparse.ArgumentParser(prog='PROG',
                                 ....
                                 formatter_class=argparse.RawDescriptionHelpFormatter)

这个方法违反了行数不应超过 80 个字符的规定。

这是 argparse 文档中的一个示例(剧透:这个其实是正确的;见下方评论):

parser = argparse.ArgumentParser(
    prog='PROG',
    formatter_class=argparse.RawDescriptionHelpFormatter,
    ....

这个方法违反了 PEP8 E128 关于续行缩进的规定。

这里还有另一种可能性:

parser = argparse.ArgumentParser(
    prog='PROG',
    formatter_class=
    argparse.RawDescriptionHelpFormatter,
    ....

这个方法违反了 PEP8 E251 关于关键字参数周围空格的规定。

(当然,这还没有考虑到我计算行字符数时假设 parser 从第一列开始,这是最理想的情况;如果我们想在一个类和/或函数内部创建一个解析器呢?)

所以,就我所知,唯一剩下的选择就是让命名空间变得杂乱:

from argparse import RawDescriptionHelpFormatter, ArgumentParser

...或者使用一个无聊的临时变量(这也会让命名空间变得杂乱):

rawformatter = argparse.RawDescriptionHelpFormatter
parser = argparse.ArgumentParser(prog='PROG',
                                 ....
                                 formatter_class=rawformatter)

我是不是漏掉了什么?我想把 RawDescriptionHelpFormatter 和 ArgumentParser 直接放在当前命名空间里并不算大问题,但这似乎是一个不必要的烦恼。

2 个回答

1

还有一些其他的变体:

from argparse import RawDescriptionHelpFormatter as formatter

parser = argparse.ArgumentFormatter(prog='PROG')
# you can reassign a parser attribute after initialization
parser.formatter_class = formatter 

不过,ArgumentParser 还有其他输入,可能会长到需要换行或者分配给不同的变量。

usage = 'PROG [-h] --foo FOO BAR etc'
description = """\
This is a long multiline description
that may require dedenting.
"""
description = textwrap.dedent(description)
parser=Argparse(usage=usage, description=description, formatter_class=formatter)

可以看看 test_argparse.py,里面展示了如何定义一个既长又复杂的解析器的多种方法。


http://bugs.python.org/issue13023 提出了一个问题:如果你想要多个格式化器的修改,比如:

这意味着我们可以传递 argparse.RawDescriptionHelpFormatter 或 argparse.ArgumentDefaultsHelpFormatter,但不能同时传递两者。

推荐的解决方案是创建格式化器的子类:

class MyFormatter(argparse.RawDescriptionHelpFormatter, 
    argparse.ArgumentDefaultsHelpformatter):
    pass

保持命名空间整洁的另一种方法是把解析器的定义放在一个函数或模块里。

http://ipython.org/ipython-doc/2/api/generated/IPython.core.magic_arguments.html

这是一个例子,展示了 IPython 如何封装 argparse,为用户提供新的API。

另一个基于 argparse 的解析器 plac 首先构建一个 cfg 字典:

https://code.google.com/p/plac/source/browse/plac_core.py

def pconf(obj):
    ...
    cfg = dict(description=obj.__doc__, 
               formatter_class=argparse.RawDescriptionHelpFormatter)
    ...
    return cfg

def parser_from(obj, **confparams):
    ...
    conf = pconf(obj).copy()
    conf.update(confparams)
    parser = ArgumentParser(**conf)
3

你的第二个例子在我看来没问题,似乎和这里的“# 悬挂缩进应该增加一个级别。”的例子相符:http://legacy.python.org/dev/peps/pep-0008/#indentation

这也和这个类似的问题/回答一致:PEP8的E128:视觉缩进下的续行缩进不足是什么?

撰写回答