关于python:用于缩进多行“if”语句的代码样式?

Code-style for indention of multi-line 'if' statement?

本问题已经有最佳答案,请猛点这里访问。

当缩进长if条件时,通常会执行如下操作(实际上,pydev是这样缩进的):

1
2
3
4
if (collResv.repeatability is None or
    collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

但是,这使得if语句启动的块与if条件的最后一部分处于相同的缩进级别,这使得我认为它非常难看/难以阅读,因为您不会立即看到块从何处开始。

我想到的其他风格:

1
2
3
4
if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

这看起来非常不一致,因为第二行的缩进量比第一行大得多,但它是可读的。

1
2
3
4
if (collResv.repeatability is None or
  collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

这也比第一个例子更易读,但是缩进不再是4的倍数,而且第二行的缩进比第一行条件的开头少,因此看起来是错误的。

因此,我的主要问题是:对于不需要过长的行(即单行条件)的情况,是否有建议的缩进样式?如果没有,你喜欢那种情况吗?


我经常通过在自己的语句中计算条件来解决这个问题:

1
2
3
4
5
condition = (collResv.repeatability is None or
             collResv.somethingElse)
if condition:
    collResv.rejected = True
    collResv.rejectCompletely()

不过,对于一个仍然相对较短的条件(如在您的特定示例中),我将使用nosklo的解决方案——这里使用的额外语句更适合于更长的条件表达式。


这就是我要做的:

1
2
3
4
if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()


这里所有先前建议的一个问题是,后续条件的逻辑运算符放在前面一行。在我看来,这会降低它的可读性。

我建议将逻辑运算符与它附加到if语句的条件放在同一行。

在我看来,这更好

1
2
3
if (None == foo
        and None == bar
        or None == foo_bar):

比这个:

1
2
3
if (None == foo and
        None == bar or
        None == foo_bar):


这是一个间接的答案——不是直接回答风格问题,而是一般来说的实际答案,所以值得一提。

我发现很少需要写多行条件。这有两个因素:

  • 不要在80列处包装代码。PEP-8对这个问题的建议是古老的,有害的;我们已经远远超过了80x25终端和编辑无法合理处理包装的时代。100列很好,120列通常也是可以接受的。
  • 如果条件变得如此之长以至于它们仍然需要包装,那么将一些逻辑从条件中移出并放入一个单独的表达式通常是合理的。这也有助于提高可读性。

通过我最近的项目,大约12kloc,只有一个条件足够长,它需要被包装;问题只是很少出现。如果您确实需要这样做,那么正如nosklo所说,将它单独缩进——正如您注意到的,将它缩进到与它下面的块相同的级别是令人困惑和难以阅读的。


PEP-8在这里似乎是矛盾的。"最大行长度"下的示例显示了括号和标准的4字符缩进的用法,"缩进"部分表示,对于函数声明,"进一步的缩进应用于清楚地将自身区分为连续行。"。我不明白为什么这只限于"def"而不是"if"。


我会这样做的。把它缩进很远,不要弄混。

1
2
3
4
if (collResv.repeatability is None or
                          collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

PEP-8建议就在这里。

http://www.python.org/dev/peps/pep-0008/缩进

建议使用以下代码

1
2
3
4
5
6
7
8
9
# Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# More indentation included to distinguish this from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

不建议使用以下代码

1
2
3
4
5
6
7
8
9
# Arguments on first line forbidden when not using vertical alignment
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)


在这种情况下,我只需:

1
2
3
4
5
if (collResv.repeatability is None or
    collResv.somethingElse):
    # do:
    collResv.rejected = True
    collResv.rejectCompletely()

PEP-8建议您缩进原始示例的方式。

现在,如果你愿意面对如此神圣的风格指南,你可以把接线员移到下一行:

1
2
3
4
if (collResv.repeatability is None
    or collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

我不太喜欢这个,实际上我发现你的原始语法非常容易阅读,而且不会花太多时间去修改缩进或换行符。


我有时使用的一个选项(尽管我没有完全出售它的可读性):

1
2
3
4
5
if (collResv.repeatability is None or
    collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()

这样可能更容易阅读:

1
2
3
4
5
6
if (
collResv.repeatability is None or
collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()