if-else python short-cut评估函数两次吗?

时间:2014-02-11 06:21:56

标签: python nonetype

假设我有一个函数getQ(x),它返回一些数字并且速度很慢。现在,如果我这样做:

x = 10
x = getQ(x) if getQ(x) >= 0 else 0
在这种情况下,

getQ会被执行两次吗?

这是:

x = getQ(x)
x = x if x >= 0 else 0

更快?

如果是这样,对于这种情况,是否会有更优雅的单线?

2 个答案:

答案 0 :(得分:5)

是的,如果结果是非负的话,getQ会被调用两次,所以第二种情况肯定会更快。

在这种特殊情况下,您可以编写x = max(getQ(x), 0)。 "将军"您正在寻找的解决方案就像是

x = (lambda x: x if x >= 0 else 0)(getQ(x))

我不建议在实际代码中使用它,但它允许您绑定一个名称,同时仍保留一个表达式。

答案 1 :(得分:1)

您可以使用dis模块,并清楚地看到在第一种情况下将调用该函数两次。

def fun1():
    ...:     x = sqrt(10) if sqrt(10)>=0 else 0
    ...:     

dis.dis(fun1)
  2           0 LOAD_GLOBAL              0 (sqrt) 
              3 LOAD_CONST               1 (10) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)  // First Call
              9 LOAD_CONST               2 (0) 
             12 COMPARE_OP               5 (>=) 
             15 POP_JUMP_IF_FALSE       30 
             18 LOAD_GLOBAL              0 (sqrt) 
             21 LOAD_CONST               1 (10) 
             24 CALL_FUNCTION            1 (1 positional, 0 keyword pair) // Second Call
             27 JUMP_FORWARD             3 (to 33) 
        >>   30 LOAD_CONST               2 (0) 
        >>   33 STORE_FAST               0 (x) 
             36 LOAD_CONST               0 (None) 
             39 RETURN_VALUE         



def fun2():
    x = sqrt(10)
    x = x if x>=10 else 0



dis.dis(fun2)
  2           0 LOAD_GLOBAL              0 (sqrt) 
              3 LOAD_CONST               1 (10) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) // Single call
              9 STORE_FAST               0 (x) 

  3          12 LOAD_FAST                0 (x) 
             15 LOAD_CONST               1 (10) 
             18 COMPARE_OP               5 (>=) 
             21 POP_JUMP_IF_FALSE       30 
             24 LOAD_FAST                0 (x) 
             27 JUMP_FORWARD             3 (to 33) 
        >>   30 LOAD_CONST               2 (0) 
        >>   33 STORE_FAST               0 (x) 
             36 LOAD_CONST               0 (None) 
             39 RETURN_VALUE