Python3 列表解析和迭代器的內存佔用過程分析

列表解析表達式

先來看一個例子~ Leetcode 171 題
解法很簡單:

sum = 0
for i in range(0, len(s):
	sum += 26 ** (len(s) - 1 - i) * (ord(s[i]) - ord("A") + 1)
return sum

那麼,這裏也可以這麼寫。

return sum([26 ** (len(s) - 1 - i) * (ord(s[i]) - ord("A") + 1) for i in range(0, len(s))])

下面的簡寫方法,我們稱作 python的列表解析表達式 。酷酷的 o(╥﹏╥)o有沒有

再來延伸看一下這麼寫的好處(內存佔用)

上代碼:

import timeit
import os
import psutil
# 準備一個5000w 元素的列表 備用
list = range(0, 50000000)

# 計算佔用內存
def show_memory_info(hint):
    pid = os.getpid()
    p = psutil.Process(pid)

    info = p.memory_full_info()
    memory = info.uss / 1024. / 1024
    print('{} memory used: {} MB'.format(hint, memory))

# 時間
start1 = timeit.default_timer()
# 1.普通方法遍歷元素,append 到新列表
list1 = []
for x in (list):
    if x == 20000000:
        show_memory_info('1')
    if x > 4:
        list1.append(x)
show_memory_info('2')
end1 = timeit.default_timer()
print('Running time: {} Seconds'.format(end1 - start1))

start2 = timeit.default_timer()

show_memory_info('3')
# 2. 生成器生成元素到新列表,注意這裏沒有賦值到新列表
(x for x in (list) if x > 4)
show_memory_info('4')
end2 = timeit.default_timer()
print('Running time: {} Seconds'.format(end2 - start2))

運行程序,得到的結果如下:

1 memory used: 783.5625 MB
2 memory used: 1945.28125 MB
Running time: 11.129049652 Seconds
3 memory used: 1945.28125 MB
4 memory used: 1945.28125 MB
Running time: 0.09404864300000071 Seconds

關注幾點:

  1. 時間上的差別1:普通遍歷時間爲9秒,而生成器遍歷 (沒有創建新列表時間爲0.09秒),這個原因在我之前的迭代和生產的對比 博客也寫過了,是因爲只調用了算法

  2. 時間上的差別2: 如果我把 list1.apped 給刪除了,也就是普通遍歷的append 操作刪除了,時間是 6s 左右 ,看來普通遍歷確實要比生成器佔用更多的內存(廢話),時間也更長

  3. 時間上的關注點3:如果我把生成器賦值 list2 = (x for x in (list) if x > 4) ,這段代碼的時間是4秒。 可得出,生成器本身生生成元素只是調用了算法,而並未賦值(實際佔用內存)

  4. 內存上的關注點: 同3所說,生成器賦值才產生內存佔用,故而更快。

思考

語法糖其實是迭代的一個延伸,合理的運用不僅可以使代碼變酷,讓別人看不懂,也是可以優化程序運行速度和內存佔用的。

發佈了210 篇原創文章 · 獲贊 124 · 訪問量 67萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章