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

时间:2008-10-08 06:19:08

标签: python coding-style if-statement

有时我会将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

但这不是很漂亮。 : - )

你能推荐一种替代方式吗?

29 个答案:

答案 0 :(得分:610)

您不需要在第二个条件行上使用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

这是Style Guide,(自2010年起)建议使用括号。

答案 1 :(得分:110)

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

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

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

它会刮掉几个字符并清楚表明这种情况并不存在细微之处。

答案 2 :(得分:51)

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

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

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

答案 3 :(得分:24)

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

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

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

另一方面,让他们扰乱我的审美意识可以作为重构的动力。

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

答案 4 :(得分:23)

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

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

if allCondsAreOK:
   do_something

答案 5 :(得分:21)

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

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

答案 6 :(得分:19)

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

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

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

答案 7 :(得分:10)

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

  

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

if

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

答案 8 :(得分:5)

这就是我的所作所为,请记住"所有"和"任何"接受一个可迭代的,所以我只是将一个长条件放在一个列表中,然后让#34; all"做这项工作。

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

if all(condition):
   do_something

答案 9 :(得分:4)

我很惊讶没有看到我的首选解决方案,

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

由于and是一个关键字,它会被我的编辑器突出显示,并且看起来与它下面的do_something完全不同。

答案 10 :(得分:4)

就个人而言,我喜欢为长if语句添加含义。我将不得不搜索代码来找到一个合适的例子,但这是我想到的第一个例子:让我说我碰巧遇到了一些古怪的逻辑,我希望根据许多变量显示某个页面。

英语:“如果登录的用户不是管理员老师,但只是一名普通老师,而且不是学生本人......”

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

当然这可能看起来很好,但阅读那些if语句是很多工作。我们如何将逻辑分配给有意义的标签。 “标签”实际上是变量名称:

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

这可能看起来很愚蠢,但您可能还有另一种情况,即只有在您显示教师面板或默认情况下用户有权访问该其他特定面板时,您才希望显示其他项目:

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

尝试编写上述条件而不使用变量来存储和标记您的逻辑,而且您最终会得到一个非常混乱,难以阅读的逻辑语句,但您也只是重复自己。虽然有合理的例外,但请记住:不要重复自己(干)。

答案 11 :(得分:3)

(我已经轻微地修改了标识符,因为固定宽度的名称并不代表真实的代码 - 至少不是我遇到的真实代码 - 并且会相信一个例子的可读性。)

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

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

由于我从your blog post about C++发现了这个问题,我将包括我的C ++风格相同:

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

答案 12 :(得分:3)

添加@krawyoti所说的......长条件闻起来因为它们难以阅读且难以理解。使用函数或变量使代码更清晰。在Python中,我更喜欢使用垂直空间,括​​起括号,并将逻辑运算符放在每行的开头,这样表达式看起来就像“浮动”。

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

如果条件需要多次评估,如while循环,则最好使用本地函数。

答案 13 :(得分:3)

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

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

最近我一直更喜欢allany函数,因为我很少混合And和Or比较,这种方法效果很好,并且具有早期失败与生成器理解的额外优势:

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

请记住传递一个可迭代的!传递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!")

更多信息:generator comprehension

答案 14 :(得分:3)

“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

答案 15 :(得分:2)

如果我们只在条件和身体之间插入一个额外的空白行,并以规范的方式完成剩下的工作怎么办?

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

    do_something

P.S。我总是使用制表符,而不是空格;我无法微调......

答案 16 :(得分:1)

我认为@ 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

答案 17 :(得分:1)

我通常做的是:

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
这样,闭合支架和结肠在视觉上标志着我们病情的结束。

答案 18 :(得分:1)

所有为if语句提供多条件的受访者都与提出的问题一样难看。你没有通过做同样的事情来解决这个问题。

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

这是一种更易读的方法

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

要我吃我的话吗?说服你,你需要多条件,我会打印出来并为了你的娱乐而吃它。

答案 19 :(得分:1)

为了完整性,还有其他一些随意的想法。如果它们适合您,请使用它们。否则,你最好不要尝试别的东西。

您也可以使用字典执行此操作:

>>> 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!"

Dunno,如果这适合你,但它是另一个需要考虑的选择。这是另一种方式:

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'

最后两个我还没有测试过,但是这些概念应该足以让你继续前进,如果那是你想要的。

(并且为了记录,如果这只是一次性事情,你可能最好使用你最初提出的方法。如果你在很多地方进行比较,这些方法可能会提高可读性足以让你对他们有点hacky这一事实感到不好。)

答案 20 :(得分:1)

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

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

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

有趣的是,当我写这篇文章并思考“问题”时,我提出了又一个的想法,它消除了函数调用的开销。为什么不通过使用额外的括号来指示我们即将进入复杂条件?再说2,给出相对于if语句主体的子条件的2个空格缩进。例如:

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

我有点喜欢这样,因为当你看着它的时候,你的脑袋里会立刻响起一声铃声说“嘿,这里有一件复杂的事情!”。是的,我知道圆括号对可读性没有帮助,但是这些条件应该很少出现,当它们出现时,你将不得不停下来仔细阅读它们(因为它们复杂)。

无论如何,我还没有看到另外两个提案。希望这有助于某人:)

答案 21 :(得分:1)

我知道这个帖子已经老了,但我有一些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警告"视觉缩进行与下一个逻辑行"相同的缩进,实际代码完全正常?它不是"过度缩进?"

...有时候我希望Python会发现子弹并且花了大括号。我想知道多年来由于偶然的错误缩进而偶然引入了多少错误......

答案 22 :(得分:1)

您可以将其拆分为两行

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

甚至一次添加一个条件。这样,至少它将杂乱与if区分开来。

答案 23 :(得分:0)

对不起,但是碰巧我对#Python的了解不如这里的任何人,但是碰巧我在3D BIM建模中编写自己的对象时发现了类似的东西,因此我将适应我的算法是python的算法。

我在这里发现的问题是双面的:

  1. 对于可能会尝试破译该脚本的人来说,我似乎很陌生。
  2. 如果更改了这些值(最可能),或者必须添加新条件(损坏的模式),代码维护将付出高昂的代价

要绕过所有这些问题,您的脚本必须像这样

param_Val01 = Value 01   #give a meaningful name for param_Val(i) preferable an integer
param_Val02 = Value 02
param_Val03 = Value 03
param_Val04 = Value 04   # and ... etc

conditions = 0           # this is a value placeholder

########
Add script that if true will make:

conditions = conditions + param_Val01   #value of placeholder is updated
########

### repeat as needed


if conditions = param_Val01 + param_Val02 + param_Val03 + param_Val04:
    do something

此方法的优点:

  1. 脚本是可读的。

  2. 脚本易于维护。

  3. conditions是对表示所需条件的值之和的1比较操作。
  4. 无需多级条件

希望对您有帮助

答案 24 :(得分:0)

如果我们的if& 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

答案 25 :(得分:0)

我通常使用:

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

答案 26 :(得分:0)

这是另一种方法:

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)

我发现当我有很长的条件时,我经常会有一个简短的代码体。在那种情况下,我只是双重缩进身体,因此:

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

答案 28 :(得分:0)

将您的条件打包到列表中,然后执行smth。像:

if False not in Conditions:
    do_something