在if语句中依赖条件评估顺序安全吗?

问题描述:

my_var可以是无时使用以下格式是不好的做法吗?在if语句中依赖条件评估顺序安全吗?

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

的问题是,'something' in my_var将抛出一个TypeError如果my_var是无。

或者我应该使用:

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

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

重新表述的问题,它的上面是Python中的最佳实践(如果有的话)?

替代品是欢迎的!

根据条件的顺序(Python reference here)安全可靠,特别是因为您指出的问题 - 能够短路评估可能会导致一系列条件中的问题,这是非常有用的。

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

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

当我看到第二个代码时,我假设编码器不理解短路评估的工作原理。 – Dana 2009-04-15 16:04:14

+1

-1:文档中没有引用:http://docs.python.org/library/stdtypes.html#boolean-operations-and-or-not – 2009-04-15 17:02:31

+0

@cfi:因为我可以在答案更改后更改我的投票,我不清楚问题在哪。 – 2011-11-22 19:12:16

这是完全安全的,我做这一切的时候。

我会去尝试/除了,但它取决于你所了解的变量。

如果您希望变量会在大多数情况下存在,那么尝试/除了少一些操作。如果你期望变量在大多数情况下都是None,那么IF语句将会减少操作。

是的,它是安全的,它是明确和很清楚的语言参考定义:

表达x and y首先评估 x;如果xfalse,则返回其值 ;否则,y评估为 并返回结果值。

表达式x or y首先评估 x;如果x为真,则返回值为 ;否则,y评估为 并返回结果值。

并非如此简单。作为一个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#(和其他人)在使用其他语言进行编码时需要非常小心的原因。

我可能是有点迂腐在这里,但我要说的是最好的答案是

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

的区别在于为None明确的检查,而不是my_varTrueFalse的隐式转换。

虽然我敢肯定,你的情况的区别并不重要,在更普遍的情况下,这将是非常可能的变量不是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用于表示默认的函数参数。