1. 程式人生 > >python中的當資料量非常大的時候,節省記憶體空間的設定方式------------------------生成器與迭代器詳解,內附示例程式碼

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("生產者")