在if语句中依靠条件评估顺序是否安全?


76

my_var可以设置为None时,使用以下格式是否不好?

if my_var and 'something' in my_var:
    #do something

问题是,'something' in my_var如果my_var为None ,将引发TypeError。

还是我应该使用:

if my_var:
    if 'something' in my_var:
        #do something

要么

try:
    if 'something' in my_var:
        #do something
except TypeError:
    pass

重新说明这个问题,以上哪一项是Python最佳实践(如果有)?

欢迎其他选择!

Answers:


93

依赖条件条件的顺序是安全的(此处是Python参考),特别是由于您指出的问题-能够短路可能导致一系列条件问题的评估是非常有用的。

大多数语言会弹出这种代码:

IF exists(variable) AND variable.doSomething()
    THEN ...

3
当我看到第二种代码时,我认为编码器不了解短路评估的工作原理。
Dana

1
-1:从文档中没有报价:docs.python.org/library/...
美国洛特

@cfi:因为我可以在答案更改后更改投票,所以我不清楚是什么问题。
S.Lott

@cfi:做任何您认为对他人最有价值的事情。我对评论的-1我的实际投票无关。有趣的是,这允许人们做出与响应的实际值无关的持久性注释。
S.Lott

1
对于每个消极的人来说,这是一个有效的问题,并非每种语言都一样。除非您使用andalso或,否则VB会同时评估这两种情况 orelse
blindguy 2015年

35

是的,它很安全,在语言参考中已明确明确地定义了它:

表达式x and y首先计算 x; 如果xfalse,则返回其值;否则,y将求值并返回结果值。

表达式x or y首先计算 x; 如果x为true,则返回其值;否则,y将求值并返回结果值。


1
弱:它不是“安全”的-绝对需要依赖于顺序。
S.Lott

4

我可能在这里有点学究,但我想说最好的答案是

if my_var is not None and 'something' in my_var:
    #do something

区别在于对的显式检查None,而不是my_varTrue或的隐式转换False

尽管我确定在您的情况下区别并不重要,但在更一般的情况下,该变量很有可能不是None但仍为False,例如整数值0或空列表。

因此,与大多数其他张贴者所说的安全性相反,我要说的是,只要您明确表示,它就是安全的。如果您不相信,请考虑这个非常人为的课程:

class Contrived(object):
    def __contains__(self, s):
        return True
    def __nonzero__(self):
        return False

my_var = Contrived()
if 'something' in my_var:
    print "Yes the condition is true"
if my_var and 'something' in my_var:
    print "But this statement won't get reached."
if my_var is not None and 'something' in my_var:
    print "Whereas this one will."

是的,我知道这不是一个实际的示例,但是实际代码中确实会发生变化,尤其是当None用于指示默认函数参数时。


当然,如果您有一个空列表或任何容器,那么执行该in操作是没有意义的。我认为OP完全正确。尽管可以构建任何东西来证明自己的观点,但我不认为任何像样的代码都应该扎根。
SilentGhost

1
是的,这是一个人为的例子,但我的主要观点是,很容易养成if var在您真正表示“ ”时说“ ”的坏习惯if var is not None。一旦养成了这种习惯,它就很容易咬人,特别是使用默认参数时。
Scott Griffiths

我认为很明显,OP的意图是要说if var,这就是他所做的。
SilentGhost

2

没那么简单。作为C#花花公子,我非常习惯执行以下操作:

if(x != null && ! string.isnullorempty(x.Name))
{
   //do something
}

上面的方法效果很好,并按预期进行了评估。但是,在VB.Net中,以下内容将产生您未预期的结果:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

上面将产生一个异常。正确的语法应该是

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

请注意非常细微的差异。这让我困惑了大约10分钟(太长了),这就是为什么在用其他语言进行编码时C#(和其他)家伙需要非常小心的原因。


1

我会尝试使用try / except,但这取决于您对变量的了解。

如果您期望变量在大多数情况下都存在,则try / except操作较少。如果您期望变量在大多数情况下都为None,那么IF语句将减少操作。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.