2014-04-22 135 views
40

假设我们想要的一些代码块被执行时都“一”和“b”等于说5,然后我们就可以像写:Python的平等检查差异

if a == 5 and b == 5: 
    # do something 

但前几天,我只是不由自主地写了一个类似的条件检查:

if a == b and b == 5: 
    # do something 

这使我想到,是两者之间有什么区别? 此外,还有一个别的办法,

if a == b == 5: 
    # do something 

有什么不同,在评估或执行或时间的过程方面有什么区别多久?还有哪一个更好,哪个更好用?

它与传递性的概念有关吗?

+3

所有这三个将在相同数量的执行时间,并且在逻辑上是等同的。就执行时间而言,三种方法中的任何一种都需要'int'类型之间的两次等式比较。就程序员而言,哪个更好,哪些更好,清晰可读。 – CoryKramer

+1

'a < b > 5'和'a> b == 5'也是可能的(我注意到Jasper引用的文档说“比较可以被任意链接”)。但我不会推荐他们。 –

+0

@TimS。 “b在a和5之间”实际上似乎相当有用,并且比'a < b and b > 5'更可读,但那只是我。我同意'a> b == 5'虽然有点不稳定.. – Cruncher

回答

41

因为它们是等价的基本上,你也可以考虑一下你的读/想想代码的方式:

if a == 5 and b == 5: 
    # do something 

可以为“如果a等于5b等于5,然后做......“。你必须认为/结论,然后a将等于b

这是对着下面的例子:

if a == b and b == 5: 
    # do something 

读取为“如果a等于bb等于5”,你必须断定这随后也a会等于5

这就是为什么我更喜欢最后一个例子:

if a == b == 5: 
    # do something 

如果你熟悉Python(感谢Itzkata)其作用是立即清除所有的三两件事必须等于(以5)。然而,如果人们在Python(但在其他语言编程技能)经验少看到这种情况,他们会评估这

if (a == b) == 5: 

这会比较整数5,这是不是第一次比较的布尔结果什么Python做,可能会导致不同的结果(例如考虑与a=0, b=0a==b==0是真实的,而(a==b) == 0

manual说:

Python中有八个比较操作。它们都有 相同的优先级(比布尔操作的优先级高)。 比较可以任意链接;例如,X <ÿ< = z是 等价于x < y和y < = Z,不同之处在于y为只计算一次 (但在这两种情况下z为不计算在所有当x < y被发现是 false)。

甚至可能有区别,例如,如果在您的示例中挥发b会产生副作用。

关于传递性,你是对的。

+0

@Jasper你能帮我在这里!假设a = 5且b = 4,那么根据第二种情况,a == b将是假的,并且下一个条件将不被检查,因此对于这个(假)条件将只有少于1个测试,即只有1个比较。而在所有其他情况下总是有2个比较。所以在这种情况下应该有一个边际的速度改善。如果我错了,请纠正我。 – Vipul

+1

如果我正确理解手册,'a == b == 5'等价于'a == b和b == 5',所以对于'a = 5','b = 4',第二个测试' b == 5'不会被执行。另见罗伯托的回答。 – Jasper

+0

你从哪里得到“Python中有八个比较运算符。”从?我数6:'<','<=','==','!=','>','> ='...我错过了哪两个? – ArtOfWarfare

6

这取决于。你可以写自己的自定义__eq__它允许您将自己比作整数,事情:“INT”

class NonNegativeInt(object): 
    def __init__(self, value): 
    if value < 0: 
     raise Exception("Hey, what the...") 
    self.value = value 

    def __eq__(self, that): 
    if isinstance(that, int): 
     return self.value == that 
    elif isinstance(that, NonNegativeInt): 
     return self.value == that.value 
    else: 
     raise ArgumentError("Not an acceptible argument", "__eq__", that) 

这将工作不同,这取决于“B”比较“A”和“B”至因此,a == b可能为false,而a == 5 and b == 5可能为True。

+9

对不起,有一个不专业的评论,但我认为''嘿,什么......鸭子“会更加pythonic IMO =)。不能帮助自己。 – luk32

15

就整数而言,在前两次比较之间,就纯粹的性能而言,没有区别。

虽然第三个比较是不同的,因为更多一点摆弄堆栈卷入。事实上,代码

import dis 

def comparison_1(a, b): 
    if a == 5 and b == 5: 
     pass 

def comparison_2(a, b): 
    if a == b and b == 5: 
     pass 

def comparison_3(a, b): 
    if a == b == 5: 
     pass 

print("*** First comparison ***") 
dis.dis(comparison_1) 

print("\n*** Second comparison ***") 
dis.dis(comparison_2) 

print("\n*** Third comparison ***") 
dis.dis(comparison_3) 

回报

*** First comparison *** 
    4   0 LOAD_FAST    0 (a) 
       3 LOAD_CONST    1 (5) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  27 
      12 LOAD_FAST    1 (b) 
      15 LOAD_CONST    1 (5) 
      18 COMPARE_OP    2 (==) 
      21 POP_JUMP_IF_FALSE  27 

    5   24 JUMP_FORWARD    0 (to 27) 
     >> 27 LOAD_CONST    0 (None) 
      30 RETURN_VALUE   

*** Second comparison *** 
    8   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (b) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  27 
      12 LOAD_FAST    1 (b) 
      15 LOAD_CONST    1 (5) 
      18 COMPARE_OP    2 (==) 
      21 POP_JUMP_IF_FALSE  27 

    9   24 JUMP_FORWARD    0 (to 27) 
     >> 27 LOAD_CONST    0 (None) 
      30 RETURN_VALUE   

*** Third comparison *** 
12   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (b) 
       6 DUP_TOP    
       7 ROT_THREE   
       8 COMPARE_OP    2 (==) 
      11 JUMP_IF_FALSE_OR_POP 23 
      14 LOAD_CONST    1 (5) 
      17 COMPARE_OP    2 (==) 
      20 JUMP_FORWARD    2 (to 25) 
     >> 23 ROT_TWO    
      24 POP_TOP    
     >> 25 POP_JUMP_IF_FALSE  31 

13   28 JUMP_FORWARD    0 (to 31) 
     >> 31 LOAD_CONST    0 (None) 
      34 RETURN_VALUE   
+3

我很惊讶Python为第三次比较生成这样复杂的代码... – nneonneo

+1

这是什么版本的Python? – Izkata

19

如果你有多个变量来进行测试,使用all可能会稍微更可读:

if all(i==5 for i in [a,b,c,d]): 
    # do something 
+0

超过2个变量的pythonic最多。 – Jasper