是时候在Python中分配变量了

时间:2018-06-26 15:04:22

标签: python variables variable-assignment assign

假设我的循环很紧:

a = func(x)
b = func2(a)

变量a在其他任何地方都没有使用。

Python是否自动编译掉对a的赋值,还是每次都要花时间进行变量赋值?换句话说,此代码是相同的,还是由于缺少分配给a的速度而稍快?

b = func2(func(x))

Python2.7与Python3的行为是否相同?

4 个答案:

答案 0 :(得分:3)

因此,使用非常有趣的dis模块,我们可以查看从您提供的python代码生成的实际字节码。为简单起见,我已将funcfunc2替换为内置函数(intfloat)。

所以我们的来源看起来像这样:

def assign():
    a = int()
    b = float(a)

相对于简化版本:

def simple():
    b = float(int())

然后从cpython 2.7解释器开始,我们可以看到从assign函数生成的字节码:

dis.dis(assign)
  2           0 LOAD_GLOBAL              0 (int)
              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (a)

  3           9 LOAD_GLOBAL              1 (float)
             12 LOAD_FAST                0 (a)
             15 CALL_FUNCTION            1
             18 STORE_FAST               1 (b)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

如您所见,没有窥视孔优化来删除不必要的中间变量,与简化方法“简单方法”的字节码相比,这会导致额外的2条指令(STORE_FAST aLOAD_FAST a) :

dis.dis(simple)
  2           0 LOAD_GLOBAL              0 (float)
              3 LOAD_GLOBAL              1 (int)
              6 CALL_FUNCTION            0
              9 CALL_FUNCTION            1
             12 STORE_FAST               0 (b)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE

对于适用于Python 3.5的CPython解释器和适用于Python 2.7的pypy解释器,这是相同的。

答案 1 :(得分:1)

使用dis模块比较字节码:看起来第二种方法产生的操作更少

import dis

print(dis.dis('a=f(2);b=g(a)'))
print(dis.dis('b=g(f(2))'))


>>>   
  1           0 LOAD_NAME                0 (f)
              2 LOAD_CONST               0 (2)
              4 CALL_FUNCTION            1
              6 STORE_NAME               1 (a)
              8 LOAD_NAME                2 (g)
             10 LOAD_NAME                1 (a)
             12 CALL_FUNCTION            1
             14 STORE_NAME               3 (b)
             16 LOAD_CONST               1 (None)
             18 RETURN_VALUE
None
  1           0 LOAD_NAME                0 (g)
              2 LOAD_NAME                1 (f)
              4 LOAD_CONST               0 (2)
              6 CALL_FUNCTION            1
              8 CALL_FUNCTION            1
             10 STORE_NAME               2 (b)
             12 LOAD_CONST               1 (None)
             14 RETURN_VALUE
None

答案 2 :(得分:0)

可以使用timeit轻松检查此类查询。这是Python2.7的结果。

root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.29 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.284 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.285 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.283 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.294 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.286 usec per loop

这显示出与其他答案一致的结果,这些答案描述了很棒的dis模块的使用。

答案 3 :(得分:-1)

实际时间将取决于功能func()func2()的作用。不是最好的例子,但是下面给出了一个快速(又脏)的测试代码:

import time

def func(x):
    return 5

def func2(a):
    return 10

t0 = time.time()
x = 10
for i in range(1,10000):
    a = func(x)
    b = func2(a)
t1 = time.time()

print("Time 1: ", t1-t0)

t2 = time.time()
x = 10
for i in range(1,10000):
    b = func2(func(x))
t3 = time.time()

print("Time 2: ", t3-t2)

以上代码的输出为:

Time 1:  0.0029211044311523438
Time 2:  0.002785921096801758

是的,在Pyhton 3中,避免分配a的实现要快一些。