python中的當資料量非常大的時候,節省記憶體空間的設定方式------------------------生成器與迭代器詳解,內附示例程式碼
鋪墊部分,首先,我們先來講一下列表生成式,如下所示
>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
這就是列表生成式,現在的資料量比較小,並不能看出什麼,當把range(10),換為更高的數字的時候,我們就會看到,他直接會將所有的列表中的內容全部打印出來,顯然,這是十分佔用記憶體的,所以,就引入了生成器的概念,示例如下
>>>(i*2 for i in range(10))
<generator object <genexpr> at 0x0000000002B5A660>
可以看到,我們只是把方括號變成了小括號,就可以產生一個生成器,返回的內容為生成器的記憶體地址,當生成的時候,他並沒有給所有的列表中的內容分配記憶體地址,而是,當用到的時候才分配記憶體,相比於列表生成式的直接分配所有記憶體地址,會更加的節省記憶體。
生成器的特點:
列表生成式是直接都生成了,而生成器則是在呼叫的時候才會生成,而且必須迴圈到那個位置的時候才可以呼叫,只記錄當前的位置,只有一個__next__()方法,取下一個內容。
>>> c=(i*2 for i in range(10))
>>> c[8]
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
c[8]
TypeError: 'generator' object is not subscriptable
我們可以看到,我們令c等於那個生成器,再直接呼叫8是不可以的,因為還沒有到那裡,但是我們可以一個一個的呼叫
>>> c.__next__()
0
>>> c.__next__()
2
>>> c.__next__()
4
>>> c.__next__()
6
>>> c.__next__()
8
上面只是講了一個簡單的生成器,當演算法比較複雜的時候,無法用for迴圈實現的時候,這個時候就可以利用函式來實現,用函式來產生一個生成器,下面我們用一個具體的例子來說明在函式中如何產生一個生成器,一步一步的解釋。
#Filename:斐波那契.py
#其實主要就通過一個關鍵字yield即可實現。
#這是一個產生斐波那契序列的函式,不用管這個序列到底是怎麼樣的,你只需要看關鍵的幾個步驟即可,關鍵步驟已加註釋
def fib(max):
n, a, b = 0, 0, 1
while n < max:
#print(b),原本在這個地方是用print列印這個b,但是,我們現在用生成器了,所以就直接給b一個稱號yield
#所有b組成的值就是一個生成器,我們可以一個一個的去呼叫它
yield b
a, b = b, a + b
n = n + 1
g = fib(6)#原來是呼叫函式,但現在fib(6)就代表一個生成器,把這個生成器起了一個名字,叫做g
while True:
#迴圈取生成器中的值,呼叫__next__()函式,一個一個取,一直到結尾
try:
x = g.__next__()
print('g:', x)
except StopIteration as e:
#這部分就是給定一個結尾,當呼叫到結尾的時候,就會產生一個異常,那麼,當抓到這個異常的時候就結束
print('Generator return value:', e.value)
break
在此兩種生成器的方式就講完了,下面將對迭代器進行講解
可迭代物件:可直接作用於for迴圈的物件叫做可迭代物件,即Iterable
迭代器:可以被next()函式呼叫,並不斷返回下一個值得物件就是迭代器,即Iterator
列表,字典之類的都是可迭代物件,但他們不是迭代器
生成器就是一個迭代器,因為可以呼叫next()函式
那麼如何將迭代物件程式設計迭代器呢?
可以呼叫iter()方法,例子如下:
>>> a=[1,2,3]
>>> b=iter(a)
>>> b.__next__()
1
>>> b.__next__()
2
>>> b.__next__()
3
>>> a.__next__()
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
a.__next__()
AttributeError: 'list' object has no attribute '__next__'
這樣就變為了迭代器,我們可以看到,a不可以呼叫__next__(),但是b可以
最後我們給一個生成器思考的例子,有興趣的可以看一下
import time
def consumer(name):
print("%s 準備吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]來了,被[%s]吃了!" %(baozi,name))
c = consumer("ChenRonghua")
c.__next__()
# b1= "韭菜餡"
# c.send(b1)
# c.__next__()
def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子開始準備做包子啦!")
for i in range(10):
time.sleep(1)
print("做了1個包子,分兩半!")
c.send(i)
c2.send(i)
producer("生產者")