簡體   English   中英

是時候在Python中分配變量了

[英]Time to assign a variable in Python

假設我有一個非常緊密的循環:

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

變量a不在其他任何地方使用。

是否Python的自動編譯掉分配給a呢,還是走的時候每次都做變量賦值? 換句話說,此代碼是否相同,還是由於缺少分配給a速度略快?

b = func2(func(x))

Python2.7和Python3的行為是否相同?

因此,使用非常有趣的dis模塊,我們可以查看從您提供的python代碼生成的實際字節碼。 為了簡單func2 ,我用內置函數( intfloat )替換了funcfunc2

因此,我們的來源如下所示:

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解釋器,這是相同的。

使用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

可以使用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模塊的其他答案顯示出一致的結果。

實際時間將取決於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要快一些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM