多行“if”语句的缩进代码风格?

41

当缩进长的 if 条件语句时,通常会像这样做(实际上,PyDev 也是这么缩进的):


当缩进长的 if 条件语句时,通常会像这样做(实际上,PyDev 也是这么缩进的):
if (collResv.repeatability is None or
    collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

然而,这会将if语句开始的块放置在与if条件的最后部分相同的缩进级别上,我认为这使得代码非常难看/难以阅读,因为你不能立即看到块的起始位置。

我考虑过一些其他的样式:

if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

这看起来相当不一致,因为第二行的缩进比第一行多得多,但是它还是可读的。

if (collResv.repeatability is None or
  collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

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


那么,我的主要问题是:在这种情况下,是否建议使用某种缩进风格,而不需要过长的行(即单行条件)? 如果没有,那么你喜欢哪种情况?


为什么collResv上没有一个方法来执行测试呢?你必须对不是self的东西进行复合条件,这可能表明你需要重构。同样,为什么名为rejectCompletely()的方法也不在对象上设置rejected属性呢? - Duncan
其实那只是一个例子。没有叫那个名字的方法 - 我只是想要一个听起来有点合理的东西,以便在方法体中有多于一行的内容。 - ThiefMaster
9个回答

29

通常情况下,我会通过在单独的语句中计算条件来解决这个问题:

condition = (collResv.repeatability is None or
             collResv.somethingElse)
if condition:
    collResv.rejected = True
    collResv.rejectCompletely()

虽然在你这个具体的例子中,对于一个相对较短的条件语句,我会选择 nosklo 的解决方案-此处使用的额外语句更适用于更长的条件表达式。


1
我认为这段代码使得阅读变得更加困难。真的需要一个变量来避免多行if语句吗? - David Ehrmann
1
这种方法的可读性取决于你的特定情况,当然高度主观。除此之外,我不会在意额外变量的问题。毕竟,变量就是为了使用简短的名称来表示更复杂的事物。额外的好处是,在调试代码时,一些“冗余”的变量非常有用。 - Oben Sonne
唯一合理的情况是当你的条件是可重复使用的时候,否则这大多数时候都是懒惰的。你可以创建一个类似于 is_valid_thing 的函数,并将其用于控制流程。 - TheBigFriezy
唯一情况下这样做才有意义的是当你的条件是可重复使用的,否则这大多是懒惰的。你可以创建一个类似is_valid_thing的函数,然后在控制流中使用它。 - undefined

17

这是我的做法:

if (collResv.repeatability is None or
        collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

13

这是一个间接回答--没有直接回答样式问题,但从一般情况来看,这是实用的答案,值得一提。

我发现很少需要编写多行条件语句。 这有两个原因:

  • 不要将代码包装在80列中。PEP-8对此的建议已经过时且有害;我们已经远离了80x25终端和无法合理处理包装的编辑器。100列没问题,120列通常也可以接受。
  • 如果条件变得如此之长以至于仍然需要换行,则通常可以将某些逻辑移到条件之外并放入单独的表达式中。 这也有助于可读性。

通过我的最近项目,大约12kloc进行搜索,只有一个条件过长,需要换行。这个问题很少出现。 如果你确实需要这样做,那么像nosklo建议的那样单独缩进--正如你注意到的那样,将其缩进到下面的块的相同级别会让人困惑且难以阅读。


29
一般而言,我同意这个观点,尽管还有好的理由坚持每行80个字符(眼睛更喜欢宽度有限的文本;可以并排处理多个文件的可能性)。 - Oben Sonne
@Oben:这是段落格式的原则,而不是代码。当你将英文段落在特定宽度下换行时,每一行都在该宽度左右;这使得宽格式难以阅读,因为你的眼睛不断地扫描整个宽度。相比之下,当你将代码在120列处换行时,大多数行都要短得多;只有少数几行比较长。与过宽段落相关的可读性问题不会发生。 - Glenn Maynard
我不认为“并排”编辑的情况有趣 - 两个80列的编辑器甚至无法以舒适的字体大小放在我的24英寸监视器上,而且在任何情况下,以80列换行会使代码变得非常丑陋,这样做根本不值得。如果人们处于这种配置中,他们可以容忍一些编辑器换行,而不是期望每个人都压缩他们的代码。 - Glenn Maynard
是的,对于连续文本来说,有一个限制宽度更为重要。不过,我(或者说我的眼睛)也更喜欢在代码中遵循这个原则 - 不过显然这只是个人偏好。 - Oben Sonne
9
如果一个开发者使用超长的行——认为在今天的屏幕上不需要将200个字符或其他内容折行——那么其他开发者可能无法在一个显示器上并排放置三个窗口,并查看格式合理的代码。超过80列基本上就像是对其他开发者施加未换行的代码一样——这与散文文本无关。仅仅因为某个作者无法将两个80列的编辑器并排放置并查看,这并不意味着其他人也不想这么做(尽管有些开发者需要较大的字体大小才能轻松阅读,这是反对长函数和长行的一个好论点......)。 - Alex North-Keys
80行代码的限制在谷歌Python编码风格指南中明确说明:https://google.github.io/styleguide/pyguide.html#Indentation,该指南广泛应用于许多不同社区。 - Tobbey

11

这里之前所有建议的问题在于,后续条件的逻辑运算符被放置在前一行。我认为这会使得代码难以阅读。

我建议将逻辑运算符放置在与其相关联的if语句条件同一行。

在我看来,这样做更好。

if (None == foo
        and None == bar
        or None == foo_bar):

比这个更:
if (None == foo and
        None == bar or
        None == foo_bar):

1
这是一条注释,而不是答案。 - augurar
4
其中一个问题是:“...你在这种情况下更喜欢什么?”我的回答回答了这个问题,所以不只是一条评论。 - Reimund
1
OP正在询问缩进问题。而你的“答案”是关于在多行表达式中放置运算符的位置。 - augurar
2
这实际上不仅仅是关于缩进的问题。问题还涉及代码风格和代码可读性,这显然是OP所关心的。 - Reimund
1
这是一条注释而不是答案,实际上更倾向于在每行结尾使用"or"、"end"或"else"。 - radtek
在我看来,任何主要论据是“依我的看法” 的答案都不是真正的答案。除非你是有资格提出官方/值得注意建议的主要来源,或者你可以引用某人/某组织的意见,否则你的意见应该是一条评论。 - Michael M.

3
我会这样做。请将其远离缩进以免混淆。
if (collResv.repeatability is None or
                          collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

PEP-8建议在这里。

http://www.python.org/dev/peps/pep-0008/#indentation

以下代码是建议的。

# 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)

以下代码不建议使用

# 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)

3

在这里PEP-8似乎有些矛盾。虽然“最大行长度”下的示例显示了括号和标准的4个字符缩进,但是“缩进”部分说,对于函数声明,“应该使用进一步的缩进来清楚地区分其作为连续行。” 我不明白为什么这只限于“def”,而不是“if”。


0

有时我会使用一个选项(尽管我并不完全认同它的可读性):

if (collResv.repeatability is None or
    collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()

可能这种方式更易读:

if (
collResv.repeatability is None or
collResv.somethingElse
):
    collResv.rejected = True
    collResv.rejectCompletely()

6
这与Python的任何风格习惯都非常不同,请不要这样做。 - Glenn Maynard
是的,我应该注意到我只在简单的个人项目中使用Python,没有其他人需要阅读。 - Blorgbeard
在我看来,无论使用哪种语言都看起来很糟糕。这就像在C语言中将){放在单独的一行上一样。 - ThiefMaster
哈哈,我也这样做(用C#)。我也不喜欢它,但其他选项我真的很讨厌 :| - Blorgbeard

0

Pep-8建议您按照原始示例的缩进方式。

现在,如果您愿意违反如此神圣的样式指南 :-) ,您可以将运算符移动到下一行:

if (collResv.repeatability is None
    or collResv.somethingElse):
    collResv.rejected = True
    collResv.rejectCompletely()

我并不是很喜欢这个,实际上我觉得你原来的语法相当容易阅读,不会花太多时间去调整缩进或换行。


0
在这种情况下,我会简单地执行以下操作:
if (collResv.repeatability is None or
    collResv.somethingElse):
    # do:
    collResv.rejected = True
    collResv.rejectCompletely()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接