python 中带有类型提示的悬挂缩进的适当缩进级别是多少?

What is the proper level of indent for hanging indent with type hinting in python?

具有多个参数和类型提示的方法的悬挂缩进的正确语法是什么?

在第一个参数下对齐

def get_library_book(self,
                     book_id: str,
                     library_id: str
                     )-> Book:

下缩一级

def get_library_book(
    self, 
    book_id: str, 
    library_id: str
) -> Book:

PEP8 支持 Indent one level below 的情况,但没有指定是否允许 Align under first parameter。它指出:

When using a hanging indent the following should be considered; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line.

仔细阅读PEP 8的前一行,"or using a hanging indent"之前的部分。

Continuation lines should align wrapped elements either vertically using Python's implicit line joining inside parentheses, brackets and braces, or using a hanging indent.

这是为了涵盖第一个“是”的示例,以及上面的第一个示例。

# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

除了 Terry 的回答,举一个来自 typeshed 的例子,它是 Python 的 GitHub 上的项目,用于用存根注释 stdlib

例如,在importlib.machinery (and in other cases if you look) annotations are done using your first form, for example中:

def find_module(cls, fullname: str,
                path: Optional[Sequence[importlib.abc._Path]]
               ) -> Optional[importlib.abc.Loader]:

PEP8 里面有很多好的想法,但我不会依赖它来决定这种关于空白的问题。当我研究 PEP8 关于空白的建议时,我发现它们是不一致的,甚至是矛盾的。

相反,我会研究适用于几乎所有编程语言的一般原则,而不仅仅是 Python。

第一个示例中显示的列对齐有很多缺点,我不在我的任何项目中使用或允许它。

一些缺点:

  • 如果更改函数名称使其长度不同,则必须重新对齐所有参数。
  • 当您进行重新调整时,您的源代码管理差异会因不必要的空白更改而变得杂乱无章。
  • 随着代码的更新和维护,您在重命名变量时很可能会错过一些对齐,从而导致代码未对齐。
  • 你得到更长的行长度。
  • 对齐方式在比例字体中不起作用。 (是的,一些开发人员更喜欢比例字体,如果您避免列对齐,您的代码在等宽字体或比例字体中同样可读。)

如果在更复杂的情况下使用列对齐,情况会变得更糟。考虑这个例子:

let mut rewrites = try_opt!(subexpr_list.iter()
                                        .rev()
                                        .map(|e| {
                                            rewrite_chain_expr(e,
                                                               total_span,
                                                               context,
                                                               max_width,
                                                               indent)
                                        })
                                        .collect::<Option<Vec<_>>>());

这是来自 Servo 浏览器的 Rust 代码,其编码风格要求这种列对齐。虽然它不是 Python 代码,但完全相同的原则适用于 Python 或几乎任何语言。

在此代码示例中,列对齐的使用如何导致糟糕的情况应该是显而易见的。如果您需要在嵌套的 rewrite_chain_expr 调用中调用另一个函数,或者有一个更长的变量名怎么办?除非你想要 非常 排长队,否则你几乎没有房间了。

将上面的版本与使用纯粹基于缩进的样式的任何一个版本(如第二个 Python 示例)进行比较:

let mut rewrites = try_opt!(
    subexpr_list
        .iter()
        .rev()
        .map( |e| {
            rewrite_chain_expr( e, total_span, context, max_width, indent )
        })
        .collect::<Option<Vec<_>>>()
);

或者,如果 rewrite_chain_expr 的参数更长,或者如果您只是想要更短的行:

let mut rewrites = try_opt!(
    subexpr_list
        .iter()
        .rev()
        .map( |e| {
            rewrite_chain_expr(
                e,
                total_span,
                context,
                max_width,
                indent
            )
        })
        .collect::<Option<Vec<_>>>()
);

相对于列对齐样式,这种纯缩进样式有很多优点,没有任何缺点。