0 前言
說到處理迴圈,我們習慣使用 for, while 等,比如依次列印每個列表中的字元:
lis = [『i』, 『love』, 『python』]
for i in lis:
print(i)
輸出:i
love
python
在列印內容位元組數較小時,全部載入記憶體後,再列印,沒有問題。可是,如果現在有成千上百萬條車輛行駛軌跡,叫你分析出其中每個客戶的出行規律,堵車情況等,假如是在單機上處理這件事。
你可能首先要面臨,也可能被你忽視,最後**都寫好後,才可能暴露出的乙個問題:outofmemory, 這在實際專案中經常遇到。
這個問題提醒我們,處理資料時,如何寫出高效利用記憶體的程式,就顯得很重要。今天,我們就來**如何高效利用記憶體,節省記憶體同時還能把事情辦好。
其實,python 已經準備好乙個模組專門用來處理這件事,它就是 itertools 模組,這裡面幾個函式的功能其實很好理解。
我不打算籠統的介紹它們所能實現的功能,而是想分析這些功能背後的實現**,它們如何做到高效節省記憶體的,python 核心的貢獻者們又是如何寫出一手漂亮的**的,這很有趣,不是嗎?
1 拼接元素
itertools 中的 chain 函式實現元素拼接,原型如下,引數 * 表示個數可變的引數
chain(iterables)
應用如下:
in [33]: list(chain([『i』,『love』],[『python』],[『very』, 『much』]))
out[33]: [『i』, 『love』, 『python』, 『very』, 『much』]
哇,不能再好用了,它有點 join 的味道,但是比 join 強,它的重點在於引數都是可迭代的例項。
那麼,chain 如何實現高效節省記憶體的呢?chain 大概的實現**如下:
def chain(*iterables):
for it in iterables:
for element in it:
yield element
以上**不難理解,chain本質返回乙個生成器,所以它實際上是一次讀入乙個元素到記憶體,所以做到最高效地節省記憶體。
2 逐個累積
返回列表的累積彙總值,原型:
accumulate(iterable[, func, *, initial=none])
應用如下:
in [36]: list(accumulate([1,2,3,4,5,6],lambda x,y: x*y))
out[36]: [1, 2, 6, 24, 120, 720]
accumulate 大概的實現**如下:
def accumulate(iterable, func=operator.add, *, initial=none):
it = iter(iterable)
total = initial
if initial is none:
try:
total = next(it)
except stopiteration:
return
yield total
for element in it:
total = func(total, element)
yield total
以上**,你還好嗎?與 chain 簡單的 yield 不同,此處稍微複雜一點,yield 有點像 return,所以 yield total那行直接就返回乙個元素,也就是 iterable 的第乙個元素,因為任何時候這個函式返回的第乙個元素就是它的第乙個。又因為 yield 返回的是乙個 generator 物件,比如名字 gen,所以 next(gen) 時,**將會執行到 for element in it:這行,而此時的迭代器 it 已經指到 iterable 的第二個元素,ok,相信你懂了!
3 漏斗篩選
它是 compress 函式,功能類似於漏斗功能,所以我稱它為漏斗篩選,原型:
compress(data, selectors)
in [38]: list(compress(『abcdefg』,[1,1,0,1]))
out[38]: [『a』, 『b』, 『d』]
容易看出,compress 返回的元素個數等於兩個引數中較短的列表長度。
它的大概實現**:
def compress(data, selectors):
return (d for d, s in zip(data, selectors) if s)
4 段位篩選
掃瞄列表,不滿足條件處開始往後保留,原型如下:
dropwhile(predicate, iterable)
應用例子:
in [39]: list(dropwhile(lambda x: x<3,[1,0,2,4,1,1,3,5,-5]))
out[39]: [4, 1, 1, 3, 5, -5]
實現它的大概**如下:
def dropwhile(predicate, iterable):
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
5 段位篩選 2
掃瞄列表,只要滿足條件就從可迭代物件中返回元素,直到不滿足條件為止,原型如下:
takewhile(predicate, iterable)
應用例子:
in [43]: list(takewhile(lambda x: x<5, [1,4,6,4,1]))
out[43]: [1, 4]
實現它的大概**如下:
def takewhile(predicate, iterable):
for x in iterable:
if predicate(x):
yield x
else:
break #立即返回
6 次品篩選
掃瞄列表,只要不滿足條件都保留,原型如下:
dropwhile(predicate, iterable)
應用例子:
in [40]: list(filte***lse(lambda x: x%2==0, [1,2,3,4,5,6]))
out[40]: [1, 3, 5]
實現它的大概**如下:
def dropwhile(predicate, iterable):
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
python節省記憶體技巧 使用 slots
slots 作用 slots 有乙個作用是 限制類例項繫結的屬性,但是它有乙個更重要的作用就是節省記憶體,當然更適用於資料量大的情況 萬量級以上 slots 節省記憶體的原理 class measurement def init self,x,y,value self.x x self.y y se...
python 百萬級別類例項實現節省記憶體
案例 某網路遊戲中,定義了玩家類player id,name,status 每當有乙個玩家,就會在伺服器建立乙個player例項 如何降低這些例項的大量例項的記憶體開銷?解決方案 定義類的 slots 屬性,它是用來宣告例項屬性名字的列表 class player object slots name...
python如何為建立大量例項節省記憶體
python如何為建立大量例項節省記憶體,具體內容如下 案例 某網路遊戲中,定義了玩家類player id,name,status,每有乙個 玩家,在伺服器程式內有乙個player的例項,當 人數很多時,將產生大量例項 百萬級別 需求 如何降低這些大量例項的記憶體開銷?如何做?首先要明白,pytho...