在“if”语句中devise多行条件?

有时候我会把条件分成几行。 最明显的做法是:

  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 

但是这不是很漂亮。 🙂

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

你不需要在你的第二条线上使用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 

但这两个都相当丑陋。

也许失去了括号( 风格指南劝阻这个虽然)?

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

这至less给你一些区别。

甚至:

 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 

这是2010年以来推荐使用括号的风格指南 。

在退化的情况下,我简单地使用了AND或OR。

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

它削减了几个字符,并明确指出,这种情况没有任何微妙之处。

有人必须在这里争取使用垂直空格! 🙂

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

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

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

是的,为了清晰起见,我们正在进行一些垂直房地产的交易。 很值得的海事组织。

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

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

这正是我在代码中解决这个问题的方法。 有一个关键字作为行中的第一个单词使条件更加可读,减less空间的数量进一步区分条件和行动。

下面是我非常个人的看法:长时间的条件(在我看来)是一种代码味道,暗示重构为布尔返回函数/方法。 例如:

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

现在,如果我find了使多线条件看起来不错的方法,那么我可能会发现自己满足于拥有它们并跳过重构。

另一方面,让他们扰乱我的审美意识就成为重构的诱因。

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

这并没有改善,但…

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

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

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

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

if语句的条件部分足够长以至于需要跨多行书写时,值得注意的是,两个字符关键字(即if )的组合,再加上一个空格,再加上一个左括号,会创build一个自然的四行缩进多行有条件的后续行。 这可能会产生一个嵌套在if语句中的缩进代码套件的视觉冲突,这个套件自然会缩进到4个空格。 这个PEP没有明确地说明如何(或者是否)在if语句中进一步从视觉上区分嵌套套件中的条件行。 在这种情况下可接受的选项包括但不限于:

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

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

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

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

由于and是一个关键字,它被我的编辑器突出显示,看起来与它下面的do_something有很大的不同。

这是我做的,记住“全部”和“任何”接受一个迭代,所以我只是把一个长的条件放在一个列表中,让“全部”做这个工作。

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

添加到@ krawyoti说…长条件气味,因为他们很难阅读和难以理解。 使用函数或variables使代码更清晰。 在Python中,我更喜欢使用垂直空间,将括号括起来,并将逻辑运算符放在每行的开头,这样expression式看起来不像“浮动”。

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

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

朴实简单,也通过pep8检查:

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

近来我一直比较喜欢allfunction,因为我很less混合使用这种方法,或者比较起来效果不错,而且还有一个额外的优点:

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

更多关于: 发电机的理解

“all”和“any”对于同types的情况很好。 但他们总是评估所有的条件。 如下例所示:

 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 

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

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

PS我总是使用标签,而不是空格; 我无法微调…

(我修改了标识符,因为固定宽度的名称并不代表真实的代码 – 至less不是我遇到的真正的代码 – 并且会相信示例的可读性。)

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

这对于“和”和“或”(他们在第二行首先是重要的)很有效,但对于其他长期条件则更是如此。 幸运的是,前者似乎是更常见的情况,而后者通常很容易用临时variables重写。 (通常不难,但在重写时可能难以或不太明显/可读地保持“和”/“或”的短路。)

因为我从你的博客文章中发现了关于C ++的这个问题,所以我将包括我的C ++风格是相同的:

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

就我个人而言,我喜欢为长时间的陈述增加意义。 我将不得不通过代码search来find一个合适的例子,但这里是第一个想到的例子:假设我碰巧遇到了一些古怪的逻辑,我想根据许多variables显示一个特定的页面。

英文:“如果login的用户不是pipe理员老师,但只是一个普通的老师,而不是学生自己…”

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

当然这可能看起来不错,但是阅读这些如果陈述是很多工作。 我们如何分配逻辑标签是有道理的。 “标签”实际上是variables名称:

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

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

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

试着写上面的条件而不使用variables来存储和标记你的逻辑,不仅会得到一个非常混乱,难以理解的逻辑陈述,而且你也只是重复自己。 虽然有合理的例外,请记住:不要重复自己(DRY)。

只是为了完整起见,还有其他一些随意的想法。 如果他们为你工作,使用它们。 否则,你可能更好的尝试别的东西。

你也可以用字典来做到这一点:

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

不知道,如果这对你有用,但它是另一个select考虑。 还有一种方法:

 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' 

最后两个我还没有testing过,但是这些概念应该足以让你走,如果这是你想要的。

(logging下来,如果这只是一次性的,那么你最好先使用你提出的方法,如果你在很多地方进行比较,这些方法可能会增加可读性你不觉得他们是有点哈克的事实这么糟糕。)

我通常做的是:

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

这种方式结束大括号和冒号视觉标记我们的条件的结束。

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

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

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

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

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

我就是这样的,因为当你看着它,一个钟就会立即响起,说: “嘿,这里有一个复杂的事情!” 。 是的,我知道括号不会帮助可读性,但是这些条件应该很less出现,而且当它们出现时,无论如何你都不得不停下来仔细阅读它们(因为它们很复杂 )。

无论如何,只有两个提案,我没有在这里看到。 希望这可以帮助别人:)

你可以把它分成两行

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

甚至一次添加一个条件。 这样,至less它把杂乱从if分离出来。

把你的条件列入清单,然后做水手。 喜欢:

 if False not in Conditions: 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 

或者如果这更清楚:

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

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

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

这是另一种方法:

 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"') 

我通常使用:

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

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

我知道这个线程是旧的,但我有一些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会咬下子弹,然后用大括号去掉。 我不知道多年来由于意外错误引起了多less错误。

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

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

这是一个更可读的方法

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

要我吃我的话吗? 说服我,你需要多条件,我会字面打印这个,吃你的娱乐。

我认为@ zkanda的解决scheme将是一个很小的转折。 如果你在自己的列表中有自己的条件和价值,你可以使用列表理解来进行比较,这会使得对于添加条件/值对更加普遍。

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

而只是用另一个运算符来抛出另一个解决scheme:

 proceed = True for c, v in zip(conditions, values): proceed &= c==v if proceed: # do something