要將生成器,先講一下列表生成式。
列表生成式
如果我們要建立乙個有規律的列表,比如說1-10:
# list1 = [1,2,3,4,5,6,7,8,9,10]
list1 = [i for i in range(1,11)] # 列表生成式
print(list1)
print(list1[2])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
3
如果我們想要的是[1,4,9,16…]呢?我們也可以用列表生成式很方便的得到:
list1 = [x * x for x in range(1,11)]
甚至我們可以定義乙個對應函式f,於是有:
list1 = [f(x) for x in range(1,11)]
生成器
我們可以發現,第一段**中,用列表生成式生成了list1,並且可以用index來訪問其中的值。那麼我們將方括號改為圓括號試一下:
list1 = (x for x in range(1,11))
print(list1)
print(list1[2])
at 0x02f26470>
traceback (most recent call last):
file "listcomprehensions.py", line 6, in print(list1[2])
typeerror: 'generator' object is not subscriptable
我們發現,list1不再是列表,而是乙個生成器物件(generator object),並且不可以用下表來訪問,那我們改怎麼訪問呢?
list1 = (x for x in range(1,11))
print(list1)
for i in list1:
print(i)
我們可以用for迴圈來獲取每乙個值。
為什麼要使用生成器呢?通過列表生成式,我們可以直接建立乙個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立乙個包含100萬個元素的列表,不僅占用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素占用的空間都白白浪費了。
所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在python中,這種一邊迴圈一邊計算的機制,稱為生成器(generato
r)。
list1 = (x for x in range(1,11))
print(list1)
print(list1.__next__())
print(list1.__next__())
print(list1.__next__())
print("break...")
print(list1.__next__())
print(list1.__next__())
print(list1.__next__())
根據上面**,我們知道,生成器會記錄之前的狀態,即使我們中斷了,再次呼叫它的next方法時,依舊會繼續上次的執行。
注意生成器的兩點:
1.只有next方法,只能往前走,不能後退;
2.只能一步步前進,不能跨大步,不能用index訪問。
將函式改為生成器
def fib(x):
n,a,b = 0,1,1
while n < x:
print(a)
a, b = b, a + b
n += 1
上面的**可以輸出指定長度的斐波拉契數列,它離生成器只有一步之遙,下面我們就將其改為生成器。
def fib(x):
n,a,b = 0,1,1
while n < x:
# print(a)
yield a
a, b = b, a + b
n += 1
g = fib(10)
print(g)
for x in g:
print(x)
上面我們同樣可以輸出指定長度的數列。生成器的結束條件有三種:
1.遇到yield關鍵字
2.遇到return
3.函式執行完
import time
def consumer(name):
print("%s prepare to eat cake" % name)
while true:
cake = yield
print("cake [%s] is ate by [%s]" % (cake,name))
def producer(name):
c = consumer("rose")
c.__next__()
print("[%s] prepare to make cake..." % name)
for i in range(1,11):
time.sleep(1)
print("[%s] has made a cake[%s]" % (name,i))
c.send(i)
producer("jack")
可迭代物件的定義:
1.可以直接作用於for迴圈的資料型別,如list,str,tuple…
2.生成器,包括帶yield的生成器函式。
這些可直接作用於for迴圈的物件統稱為可迭代物件(iterable)
我們可以用isinstance來判斷是否是可迭代物件(collections快廢棄了)。
from collections import iterable
print(isinstance(,iterable)) # true
print(isinstance("abc",iterable)) # true
print(isinstance(10,iterable)) # false
print(isinstance((x for x in range(10)),iterable)) # true
迭代器的定義:可以被next()函式呼叫並不斷返回下乙個值的物件稱為迭代器。
注意:1.生成器一定是迭代器
2.迭代器一定是可迭代物件
3.可迭代物件不一定是迭代器(可以作用於for迴圈但是沒有next方法)
from collections import iterator
print(isinstance(,iterator)) # false
print(isinstance("abc",iterator)) # false
print(isinstance(10,iterator)) # false
print(isinstance((x for x in range(10)),iterator)) # true
將可迭代物件變為迭代器
我們可以使用iter方法將可迭代物件變為迭代器:
from collections import iterator
print(isinstance(iter(),iterator)) # true
print(isinstance(iter("abc"),iterator)) # true
iterator物件表示乙個資料流,可以不斷的用next方法獲取下乙個資料,但是我們無法獲取其長度,它的計算是惰性的,只有在需要時才會計算下乙個資料。 python之生成器和迭代器
迭代 遍歷挨個取元素 a 1,2,3,4,5,6 for i in a print i 1,2,3,4,5,6 可迭代物件 實現了迭代器的物件 在產生這個物件的類中定義了 iter 方法 迭代器 迭代器在類中實現了兩個物件 iter 方法 返回迭代器物件本身 next 方法 返回下乙個元素 這裡需要...
python之生成器和迭代器
生成器表示式 返回乙個物件,這個物件只有在需要的時候才產生結果 生成器函式 為什麼叫生成器函式?因為它隨著時間的推移生成了乙個數值佇列。一般的函式在執行完畢之後會返回乙個值然後退出,但是生成器函式會自動掛起,然後重新拾起急需執行,他會利用yield關鍵字關起函式,給呼叫者返回乙個值,同時保留了當前的...
PYTHON之迭代器和生成器
所謂迭代,就是乙個迴圈,厲遍資料結構 列表,字典,元組等 內元素的過程。字串,列表,字典,元組,集合都是可迭代物件。而迭代器是用與迭代操作 for迴圈 的物件。可迭代物件通過 iter 方法轉變成迭代器,迭代器可以通過next 方法不斷返回下乙個元素直至結束。迭代器的優勢在於它不像列表那樣會預先就把...