Python 節省記憶體的迴圈寫法 一

2021-09-29 23:39:46 字數 3419 閱讀 1029

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...