在'if'语句中设置多行条件的样式?

Eli*_*sky 618 python if-statement coding-style

有时我会将ifs中的长条件分成几行.最明显的方法是:

  if (cond1 == 'val1' and cond2 == 'val2' and
      cond3 == 'val3' and cond4 == 'val4'):
      do_something
Run Code Online (Sandbox Code Playgroud)

视觉上不是很吸引人,因为动作与条件相融合.但是,这是使用4个空格的正确Python缩进的自然方式.

目前我正在使用:

  if (    cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
      do_something
Run Code Online (Sandbox Code Playgroud)

但这不是很漂亮.:-)

你能推荐另一种方式吗?

Har*_*mbe 679

您不需要在第二个条件行上使用4个空格.也许用:

if (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something
Run Code Online (Sandbox Code Playgroud)

另外,不要忘记空格比您想象的更灵活:

if (   
       cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
if    (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something
Run Code Online (Sandbox Code Playgroud)

但这两个都相当难看.

也许会丢失括号(虽然风格指南不鼓励这样)?

if cond1 == 'val1' and cond2 == 'val2' and \
   cond3 == 'val3' and cond4 == 'val4':
    do_something
Run Code Online (Sandbox Code Playgroud)

这至少给你一些区别.

甚至:

if cond1 == 'val1' and cond2 == 'val2' and \
                       cond3 == 'val3' and \
                       cond4 == 'val4':
    do_something
Run Code Online (Sandbox Code Playgroud)

我想我更喜欢:

if cond1 == 'val1' and \
   cond2 == 'val2' and \
   cond3 == 'val3' and \
   cond4 == 'val4':
    do_something
Run Code Online (Sandbox Code Playgroud)

这是样式指南,(自2010年起)建议使用括号.

  • 请注意,PEP 8不推荐使用尾随\解决方案.一个原因是,如果在编辑器中未显示空格而错误地添加空格,并且代码在语法上会变得不正确. (40认同)
  • 这是错误的,样式指南说"通过在括号中包装表达式,可以在多行中分解长行.这些应该优先使用反斜杠来表示行继续." 你可以在这里看到:http://www.python.org/dev/peps/pep-0008/#maximum-line-length (14认同)
  • @joshcartme PEP在http://hg.python.org/peps/rev/7a48207aaab6更改为明确阻止反斜杠.我会更新答案. (8认同)
  • 谢谢,更新您的示例可能是一个好主意,因为现在不推荐它们.我试图自己解决这个问题,并且对你的答案和风格指南(因此我的评论)之间的差异感到困惑.我不仅仅是想要迂腐. (3认同)
  • [PEP 8](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-binary-operator)现在不鼓励在`还有`和`if`。 (3认同)
  • 作为风格注释,我觉得当“and”和“or”继续该行而不是跟随上一行时,条件语句更具可读性。 (2认同)

S.L*_*ott 116

我在退化的情况下使用了以下内容,它只是简单的AND或OR.

if all( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

if any( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):
Run Code Online (Sandbox Code Playgroud)

它削减了一些角色,并清楚地表明这种情况没有微妙之处.

  • shortcirtuiting并不总是很快.虽然不是很好的编码实践,但你可能有这样的代码:`if destroy_world and DestroyTheWorld()== world_is_destroyed:...`.太好了,现在你刚刚意外地摧毁了这个世界.你怎么能? (59认同)
  • 如果你不关心短路,那没关系. (19认同)
  • 我很惊讶这有这么多赞成票。这个答案完全忽略了关于样式*多行*条件的原始问题。 (8认同)
  • 这是一种有趣的方法.但是没有解决长期条件的问题 (3认同)
  • 这个表情不是懒惰。因此,如果某些保护条件之后可能会失败,则这并不等效。 (2认同)

Kev*_*tle 54

有人必须在这里支持使用垂直空白!:)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()
Run Code Online (Sandbox Code Playgroud)

这使得每个条件都清晰可见.它还可以更清晰地表达更复杂的条件:

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()
Run Code Online (Sandbox Code Playgroud)

是的,为了清晰起见,我们正在对一些垂直房地产进行折衷.非常值得IMO.

  • 这似乎并不美观,也不兼容PEP8.PEP8说,打破二元运算符(例如`和`以及`或`)的首选位置是_after_运算符,而不是之前的运算符. (18认同)
  • 请不要这样做.它不仅不是"PEP8",而且更难以确定您正在链接的逻辑运算.如果它通过代码审查来到我的办公桌,我会不及格. (11认同)
  • 截至当前版本的PEP8,在二元运算符之前或之后中断[被认为是可接受的](http://legacy.python.org/dev/peps/pep-0008/#should-a-line-break-before -or-after-a-binary-operator),并且在运算符被认为更适合新代码之前. (9认同)
  • @ChristopherMedrela是否说明了背后的理由?我认为在逻辑运算符之前放置一个换行符要清楚得多 (6认同)
  • 将oprerator放在第一位在节点世界中非常普遍.理由是我们在左边注意和阅读的东西比右边的东西要快得多 - 至少在西方文化中是这样.在JavaScript中非常有效,忘记的逗号可能会导致无提示错误. (4认同)
  • @Urda我不同意.将二元运算符放在行的开头而不是最后的IMO使得它更清楚意图是什么.在上面的第二个例子中,我认为很明显``和`的操作数在被第一个条件"或"之前被组合在一起.但也许我这么认为是因为我喜欢Lisp ...... (3认同)
  • 我最喜欢这个答案,因为*禅宗的Python*`可读性很重要.`特殊情况不足以打破规则."虽然实用性超过了纯度.https://www.python.org/dev/PEPS/PEP-0020 / (2认同)

Dee*_*tan 24

当我有一个非常大的if条件时,我更喜欢这种风格:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()
Run Code Online (Sandbox Code Playgroud)

  • 截至2016年:`几十年来,推荐的风格是在二元运营商之后打破.但是这会以两种方式损害可读性......"在Python代码中,只要约定在本地一致,就允许在二元运算符之前或之后中断.对于新代码,建议使用Knuth的风格.(Knuth的风格是与运营商一起开始的). (6认同)
  • 请注意,在行的开头使用`和`和`或'运算符违反[PEP 0008](https://www.python.org/dev/peps/pep-0008/),其中声明*"首选打破二元运算符的地方是在运算符之后,而不是在它之前."*.我喜欢在自己的行上使用右括号和冒号来将if条件与正文分开(并且完全可以这样做,同时将布尔运算符保持在符合PEP-0008的行的末尾). (4认同)
  • +1用于保持缩进位置,您可以在其中跟踪它们。我喜欢python并经常使用它,但是我一直被迫如此缩进而感到烦恼。即使做得好,多线产品也确实会破坏美观。 (2认同)

kra*_*oti 24

这是我个人的看法:长期条件(在我看来)是一种代码气味,暗示重构为布尔返回的函数/方法.例如:

def is_action__required(...):
    return (cond1 == 'val1' and cond2 == 'val2'
            and cond3 == 'val3' and cond4 == 'val4')
Run Code Online (Sandbox Code Playgroud)

现在,如果我找到一种方法使多线条件看起来很好,我可能会发现自己满足于拥有它们并跳过重构.

另一方面,让他们扰乱我的审美意识就是对重构的一种激励.

因此,我的结论是,多线条件应该看起来很丑陋,这是避免它们的动机.


Fed*_*oni 23

这并没有改善太多,但......

allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                 cond3 == 'val3' and cond4 == 'val4')

if allCondsAreOK:
   do_something
Run Code Online (Sandbox Code Playgroud)

  • 布莱恩,我有点不同意.将变量用于计算的中间结果可以使代码更容易理解,并且在编译语言中不会对性能产生任何影响.它可能会在python中完成,但如果性能非常重要,我根本不会使用python. (9认同)
  • @MarkBaker 我曾经同意你写的内容,直到我读到 Martin Fowlers“重构”。他提出了一个很好的论点,即此类中间变量造成的弊大于利。它们会抑制后续的重构。没有它们会导致更函数式的编程风格,这非常适合重构。这让我感到惊讶,但我相信他是对的,并且此后一直努力从我的代码中消除像这样的不必要的中间体 - 即使它们被多次使用。 (2认同)
  • 很好,但为什么是驼峰式的?!:) (2认同)

Dzi*_*inX 19

我建议将and关键字移动到第二行,并将包含条件的所有行缩进两个空格而不是四个:

if (cond1 == 'val1' and cond2 == 'val2'
  and cond3 == 'val3' and cond4 == 'val4'):
    do_something
Run Code Online (Sandbox Code Playgroud)

这正是我在代码中解决这个问题的方法.将关键字作为行中的第一个单词使条件更具可读性,减少空格数可进一步区分条件和操作.

  • 我在Gries或Djikstra的某个地方读过,把逻辑运算符放在行的前面 - 使得更明显 - 有帮助.自90年代以来,我一直在这样做.它有帮助. (9认同)
  • 请注意,样式指南建议将条件放在行尾. (7认同)
  • PEP8 [不再推荐](http://legacy.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator)将条件赋予行的结尾. (6认同)
  • 这是真的,虽然我从未同意过这一点.毕竟,这只是一个指南. (3认同)

Mar*_*ery 10

似乎值得引用PEP 0008(Python的官方风格指南),因为它以适度的长度评论这个问题:

if-statement 的条件部分足够长以要求它跨多行写入时,值得注意的是两个字符关键字(即if)的组合,加上一个空格,加上一个左括号创建一个自然的4-多行条件的后续行的空格缩进.这可能会与嵌套在if-statement中的缩进代码集产生视觉冲突,该代码集自然也会缩进到4个空格.该PEP没有明确地说明如何(或是否)进一步在视觉上区分这些条件线与if-statement 内的嵌套套件.在这种情况下可接受的选择包括但不限于:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()
Run Code Online (Sandbox Code Playgroud)

注意上面引用中的"不限于"; 除了风格指南中提出的方法之外,在这个问题的其他答案中提出的一些方法也是可以接受的.

  • 同样值得强调的是,PEP8明确表明其立场为**这个PEP没有明确地说明如何(或是否)进一步在视觉上区分这些条件线与if-statement内的嵌套套件.在这种情况下可接受的选择包括但不限于:...(剪断)**所以,停止争论,选择你喜欢的东西! (2认同)

zka*_*nda 7

这就是我所做的,记住"所有"和"任何"接受一个可迭代的,所以我只是在列表中放入一个长条件并让"all"完成工作.

condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']

if all(condition):
   do_something
Run Code Online (Sandbox Code Playgroud)


rge*_*ito 6

就我个人而言,我喜欢为长 if 语句添加含义。我必须搜索代码才能找到合适的示例,但这是我想到的第一个示例:假设我碰巧遇到了一些奇怪的逻辑,我想根据许多变量显示某个页面。

中文: “如果登录的用户不是管理员教师,而只是普通教师,并且本身不是学生……”

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()
Run Code Online (Sandbox Code Playgroud)

当然,这看起来不错,但是阅读这些 if 语句是一项繁重的工作。我们将逻辑分配给有意义的标签怎么样?“标签”实际上是变量名:

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()
Run Code Online (Sandbox Code Playgroud)

这可能看起来很愚蠢,但您可能还有另一种情况,当且仅当您显示教师面板或者用户默认情况下有权访问其他特定面板时,您只想显示另一个项目:

if displayTeacherPanel or user.canSeeSpecialPanel():
    showSpecialPanel()
Run Code Online (Sandbox Code Playgroud)

尝试在不使用变量来存储和标记逻辑的情况下编写上述条件,不仅会得到非常混乱、难以阅读的逻辑语句,而且还会重复自己。虽然存在合理的例外情况,但请记住:不要重复自己 (DRY)。


Tho*_*ner 6

简单明了,也通过了 pep8 检查:

if (
    cond1 and
    cond2
):
    print("Hello World!")
Run Code Online (Sandbox Code Playgroud)

最近,我一直更喜欢allandany函数,因为我很少混合 And 和 Or 比较,这效果很好,并且具有通过生成器理解提前失败的额外优势:

if all([
    cond1,
    cond2,
]):
    print("Hello World!")
Run Code Online (Sandbox Code Playgroud)

只需记住传递一个可迭代对象即可!传入 N 个参数是不正确的。

注意:any就像多次or比较,all就像多次and比较。


这与生成器理解很好地结合在一起,例如:

# Check if every string in a list contains a substring:
my_list = [
    'a substring is like a string', 
    'another substring'
]

if all('substring' in item for item in my_list):
   print("Hello World!")

# or

if all(
    'substring' in item
    for item in my_list
):
    print("Hello World!")
Run Code Online (Sandbox Code Playgroud)

更多内容:生成器理解


Apa*_*ala 5

再加上@krawyoti 所说的……长时间条件的气味是因为它们难以阅读和理解。使用函数或变量使代码更清晰。在 Python 中,我更喜欢使用垂直空格、括起括号,并将逻辑运算符放在每行的开头,这样表达式就不会像“浮动”一样。

conditions_met = (
    cond1 == 'val1' 
    and cond2 == 'val2' 
    and cond3 == 'val3' 
    and cond4 == 'val4'
    )
if conditions_met:
    do_something
Run Code Online (Sandbox Code Playgroud)

如果需要多次评估条件(如在while循环中),则最好使用局部函数。