代码之家  ›  专栏  ›  技术社区  ›  Eli Bendersky

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

  •  529
  • Eli Bendersky  · 技术社区  · 16 年前

    有时我打破了长期的条件 if 在几行上。最明显的方法是:

      if (cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
          do_something
    

    视觉上不是很吸引人,因为动作与环境融合在一起。但是,使用正确的4个空格的python缩进是很自然的方法。

    目前我正在使用:

      if (    cond1 == 'val1' and cond2 == 'val2' and
              cond3 == 'val3' and cond4 == 'val4'):
          do_something
    

    但这不是很漂亮。-)

    你能推荐另一种方法吗?

    30 回复  |  直到 6 年前
        1
  •  571
  •   mardlin    9 年前

    第二个条件行不需要使用4个空格。也许用:

    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
    if    (cond1 == 'val1' and cond2 == 'val2' and 
           cond3 == 'val3' and cond4 == 'val4'):
        do_something
    

    不过,这两个都相当难看。

    可能会失去括号 Style Guide 但不鼓励这样做?

    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
    

    我想我更喜欢:

    if cond1 == 'val1' and \
       cond2 == 'val2' and \
       cond3 == 'val3' and \
       cond4 == 'val4':
        do_something
    

    这里是 风格指南 建议使用括号。

        2
  •  105
  •   S.Lott    16 年前

    在退化的情况下,我使用了以下方法:它是简单的和是或是。

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

    它剃掉了几个字符,并清楚地表明,没有微妙的条件。

        3
  •  48
  •   Kevin Little    16 年前

    某人 这里必须支持使用垂直空格!:)

    if (     cond1 == val1
         and cond2 == val2
         and cond3 == val3
       ):
        do_stuff()
    

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

    if (    cond1 == val1
         or 
            (     cond2_1 == val2_1
              and cond2_2 >= val2_2
              and cond2_3 != bad2_3
            )
       ):
        do_more_stuff()
    

    是的,为了清楚起见,我们正在进行一些垂直房地产交易。我觉得很值得。

        4
  •  23
  •   Luke H Gautam    9 年前

    这是我个人的看法:长时间条件(在我看来)是一种代码味道,它建议重构为返回布尔函数/方法。例如:

    def is_action__required(...):
        return (cond1 == 'val1' and cond2 == 'val2'
                and cond3 == 'val3' and cond4 == 'val4')
    

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

    另一方面,让它们扰乱了我的审美意识,这是对重构的激励。

    因此,我的结论是,多行条件看起来应该很糟糕,这是避免它们的一个诱因。

        5
  •  20
  •   Federico A. Ramponi    16 年前

    这并没有改善太多,但是…

    allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                     cond3 == 'val3' and cond4 == 'val4')
    
    if allCondsAreOK:
       do_something
    
        6
  •  19
  •   Dzinx    16 年前

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

    if (cond1 == 'val1' and cond2 == 'val2'
      and cond3 == 'val3' and cond4 == 'val4'):
        do_something
    

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

        7
  •  19
  •   gitaarik    6 年前

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

    if (
        expr1
        and (expr2 or expr3)
        and hasattr(thingy1, '__eq__')
        or status=="HappyTimes"
    ):
        do_stuff()
    else:
        do_other_stuff()
    
        8
  •  10
  •   Mark Amery Harley Holcombe    10 年前

    这似乎值得一提 PEP 0008 (python的官方风格指南),因为它对这个问题的评论篇幅不大:

    if -语句足够长,需要跨多行写入,值得注意的是,两个字符的关键字(即 如果 ,再加上一个空格,再加上一个左括号,为多行条件的后续行创建一个自然的4空间缩进。这可能会与嵌套在 如果 -语句,也将自然缩进为4个空格。对于如何(或是否)进一步从视觉上区分这些条件行与 如果 -声明。这种情况下可接受的选项包括但不限于:

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

    请注意上述引文中的“不限于”,除了样式指南中建议的方法外,其他问题答案中建议的一些方法也是可以接受的。

        9
  •  5
  •   zkanda    10 年前

    这就是我要做的,记住“所有”和“任何”都接受一个不可数,所以我只是把一个长条件放在一个列表中,让“所有”来做这个工作。

    condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']
    
    if all(condition):
       do_something
    
        10
  •  4
  •   Marius Gedminas    14 年前

    我很惊讶没有看到我喜欢的解决方案,

    if (cond1 == 'val1' and cond2 == 'val2'
        and cond3 == 'val3' and cond4 == 'val4'):
        do_something
    

    自从 and 是一个关键字,它会被我的编辑器突出显示,看起来与下面的“做什么”完全不同。

        11
  •  3
  •   Anders Waldenborg    16 年前

    “all”和“any”对于同一类型的许多情况都很好。但他们总是评估所有条件。如本例所示:

    def c1():
        print " Executed c1"
        return False
    def c2():
        print " Executed c2"
        return False
    
    
    print "simple and (aborts early!)"
    if c1() and c2():
        pass
    
    print
    
    print "all (executes all :( )"
    if all((c1(),c2())):
        pass
    
    print
    
        12
  •  3
  •   Fred Nurk    14 年前

    (我略微修改了标识符,因为固定宽度的名称不能代表真正的代码,至少不能代表我遇到的真正的代码,并且会掩盖示例的可读性。)

    if (cond1 == "val1" and cond22 == "val2"
    and cond333 == "val3" and cond4444 == "val4"):
        do_something
    

    这对于“和”和“或”(重要的是它们在第二行是第一行)很有效,但对于其他长的条件则不那么有效。幸运的是,前者似乎是更常见的情况,而后者通常很容易用临时变量重写。(通常不难,但在重写时要保持“and”/“or”的短路可能很困难,或者不太明显/可读。)

    自从我发现这个问题 your blog post about C++ 我将包含我的C++风格是相同的:

    if (cond1 == "val1" and cond22 == "val2"
    and cond333 == "val3" and cond4444 == "val4") {
        do_something
    }
    
        13
  •  3
  •   Apalala    14 年前

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

    conditions_met = (
        cond1 == 'val1' 
        and cond2 == 'val2' 
        and cond3 == 'val3' 
        and cond4 == 'val4'
        )
    if conditions_met:
        do_something
    

    如果需要对条件进行多次评估,如 while 循环,然后使用局部函数是最好的。

        14
  •  3
  •   rgenito    12 年前

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

    英语:“如果登录用户不是管理员教师,而是普通教师,而不是学生本人…”

    if not user.isAdmin() and user.isTeacher() and not user.isStudent():
        doSomething()
    

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

    displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
    if displayTeacherPanel:
        showTeacherPanel()
    

    这可能看起来很愚蠢,但您可能还有另一个条件,即仅当且仅当您正在显示教师面板或用户默认可以访问其他特定面板时,才希望显示其他项目:

    if displayTeacherPanel or user.canSeeSpecialPanel():
        showSpecialPanel()
    

    尝试在不使用变量存储和标记逻辑的情况下编写上述条件,不仅会导致逻辑语句非常混乱、难以阅读,而且还会重复自己的操作。尽管有一些合理的例外,但请记住:不要重复你自己(干)。

        15
  •  3
  •   Community CDub    8 年前

    简单明了,还通过了PEP8检查:

    if (
        cond1 and
        cond2
    ):
        print("Hello World!")
    

    最近我更喜欢 all any 函数,因为我很少混合和和/或比较,所以它工作得很好,而且还有一个额外的优点,那就是在生成器理解的早期失败:

    if all([
        cond1,
        cond2,
    ]):
        print("Hello World!")
    

    只需记住传递一个不可重复的!传入n个参数不正确。

    注: 任何 就像很多 or 比较, 全部的 就像很多 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!")
    

    更多关于: generator comprehension

        16
  •  2
  •   Federico A. Ramponi    16 年前

    如果我们只在条件和身体之间插入一个额外的空行,其余的以规范的方式进行呢?

    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
    
        do_something
    

    另外,我总是使用制表符,而不是空格;我不能微调…

        17
  •  1
  •   Jason Baker    16 年前

    为了完整起见,只是其他一些随机的想法。如果他们为你工作,就用他们。否则,你最好试试别的。

    你也可以用字典来做这个:

    >>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
    >>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
    >>> x == y
    True
    

    此选项更复杂,但您也可能会发现它很有用:

    class Klass(object):
        def __init__(self, some_vars):
            #initialize conditions here
        def __nonzero__(self):
            return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                    self.cond3 == 'val3' and self.cond4 == 'val4')
    
    foo = Klass()
    if foo:
        print "foo is true!"
    else:
        print "foo is false!"
    

    不知道这是否对你有用,但这是另一个可以考虑的选择。还有一种方法:

    class Klass(object):
        def __init__(self):
            #initialize conditions here
        def __eq__(self):
            return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                   self.cond3 == 'val3' and self.cond4 == 'val4')
    
    x = Klass(some_values)
    y = Klass(some_other_values)
    if x == y:
        print 'x == y'
    else:
        print 'x!=y'
    

    最后两个我还没有测试过,但是如果你想要的话,这些概念应该足够让你去做。

    (根据记录,如果这只是一次性的事情,你可能会更好地使用你最初提出的方法。如果您在很多地方进行比较,这些方法可能会增强可读性,使您不会因为它们有点黑客行为而感到不安。)

        18
  •  1
  •   tomekwi    11 年前

    我通常做的是:

    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'
       ):
        do_something
    

    这样,右大括号和冒号就可以直观地标记我们的条件的结束。

        19
  •  1
  •   El Ninja Trepador    10 年前

    我也一直在努力寻找一个合适的方法来做这件事,所以我只是想出了一个主意(不是银弹,因为这主要是一个品味问题)。

    if bool(condition1 and
            condition2 and
            ...
            conditionN):
        foo()
        bar()
    

    我在这个解决方案中发现了一些与我见过的其他解决方案相比的优点,也就是说,您得到了一个额外的4个缩进空间(bool),允许所有条件垂直对齐,并且if语句的主体可以以清晰(ish)的方式缩进。这也保留了布尔运算符的短路评估的好处,但当然增加了基本上不做任何事情的函数调用的开销。你可以(有效地)争辩说,任何返回其参数的函数都可以在这里使用,而不是bool,但正如我所说,这只是一个想法,最终是一个品味问题。

    有趣的是,当我写这篇文章并思考“问题”时,我想到了 另一种 IDEA,它消除了函数调用的开销。为什么不指出我们将要使用额外的括号对来输入一个复杂的条件呢?再多说2次,就可以对if语句体的子条件进行2个空格的缩进。例子:

    if (((foo and
          bar and
          frob and
          ninja_bear))):
        do_stuff()
    

    我有点喜欢这样,因为当你看着它的时候,一个钟声立刻在你的脑海里响起 “嘿,这里发生了一件复杂的事情!” . 是的,我知道括号对可读性没有帮助,但是这些条件应该很少出现,而且当它们出现时,无论如何,你必须停下来仔细阅读它们(因为它们 复杂的 )

    不管怎样,还有两个我在这里没有看到的建议。希望这能帮助别人:)

        20
  •  1
  •   SarcasticSully    9 年前

    你可以把它分成两行

    total = cond1 == 'val' and cond2 == 'val2' and cond3 == 'val3' and cond4 == val4
    if total:
        do_something()
    

    或者一次添加一个条件。这样,至少可以把杂乱和 if .

        21
  •  1
  •   SMGreenfield    8 年前

    我知道这个线程很旧,但是我有一些python 2.7代码,pycharm(4.5)仍然抱怨这个案例:

    if foo is not None:
        if (cond1 == 'val1' and cond2 == 'val2' and
            cond3 == 'val3' and cond4 == 'val4'):
                # some comment about do_something
                do_something
    

    即使PEP8警告“视觉上缩进的行与下一个逻辑行具有相同的缩进量”,实际代码是否完全正常?它不是“过度缩进”?

    …有时候我希望巨蟒咬住子弹,戴上大括号就走了。我想知道在过去的几年中,有多少错误是由于意外的错误缩进而被意外引入的…

        22
  •  1
  •   ryanjdillon    8 年前

    我认为@zkanda的解决方案很好,只要稍微改变一下。如果您在各自的列表中有自己的条件和值,那么可以使用列表理解来进行比较,这将使添加条件/值对的情况更加普遍。

    conditions = [1, 2, 3, 4]
    values = [1, 2, 3, 4]
    if all([c==v for c, v in zip(conditions, values)]):
        # do something
    

    如果我真的想硬编码这样的语句,为了易读性,我会这样写:

    if (condition1==value1) and (condition2==value2) and \
       (condition3==value3) and (condition4==value4):
    

    把另一个解决方案扔出去 iand operator :

    proceed = True
    for c, v in zip(conditions, values):
        proceed &= c==v
    
    if proceed:
        # do something
    
        23
  •  0
  •   psihodelia    15 年前

    把你的条件列成一个清单,然后做smth。像:

    if False not in Conditions:
        do_something
    
        24
  •  0
  •   xorsyst    14 年前

    我发现当我有长的条件时,我通常有一个短的代码体。在这种情况下,我只需要对主体进行两次缩进,这样:

    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            do_something
    
        25
  •  0
  •   Dima Tisnek    13 年前
      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
    

    在这种情况下,没有理由缩进应该是4的倍数,例如,请参见“与开始分隔符对齐”:

    http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Indentation#Indentation

        26
  •  0
  •   user1487551    10 年前

    另一种方法是:

    cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
    if all([eval(i) for i in cond_list]):
     do something
    

    这也使得在不更改if语句的情况下轻松添加另一个条件变得容易,只需在列表中附加另一个条件:

    cond_list.append('cond5=="val5"')
    
        27
  •  0
  •   Artur Gaspar    10 年前

    我通常使用:

    if ((cond1 == 'val1' and cond2 == 'val2' and
         cond3 == 'val3' and cond4 == 'val4')):
        do_something()
    
        28
  •  0
  •   Gautam    9 年前

    如果我们的if&an else条件必须在其中执行多个语句,那么我们可以如下编写。 每当我们有if-else示例时,其中包含一个语句。

    谢谢,这对我有用。

    #!/usr/bin/python
    import sys
    numberOfArgument =len(sys.argv)
    weblogic_username =''
    weblogic_password = ''
    weblogic_admin_server_host =''
    weblogic_admin_server_port =''
    
    
    if numberOfArgument == 5:
            weblogic_username = sys.argv[1]
            weblogic_password = sys.argv[2]
            weblogic_admin_server_host =sys.argv[3]
            weblogic_admin_server_port=sys.argv[4]
    elif numberOfArgument <5:
            print " weblogic UserName, weblogic Password and weblogic host details are Mandatory like, defalutUser, passwordForDefaultUser, t3s://server.domainname:7001 ."
            weblogic_username = raw_input("Enter Weblogic user Name")
            weblogic_password = raw_input('Enter Weblogic user Password')
            weblogic_admin_server_host = raw_input('Enter Weblogic admin host ')
            weblogic_admin_server_port = raw_input('Enter Weblogic admin port')
    #enfelif
    #endIf
    
        29
  •  0
  •   Stof    8 年前

    所有也为国际单项体育联合会的声明提供多个条件的受访者,都和问题提出时一样丑陋。你不能通过做同样的事情来解决这个问题。

    即使是PEP 0008的答案也是令人厌恶的。

    这里有一个更易读的方法

    condition = random.randint(0, 100) # to demonstrate
    anti_conditions = [42, 67, 12]
    if condition not in anti_conditions:
        pass
    

    想让我收回我的话吗?让我相信你需要多个条件,我会把它打印出来,然后吃它来娱乐你。

        30
  •  0
  •   Alex    6 年前

    我想这是最易读的选择:

    for pet in zoo:
        cute = every_pet()
        furry = hair is 'over9000'
        small = size < min_size
        if cute and furry and small:
            return 'I need to feed it!'