一绵患、可迭代對象(iterable)
現(xiàn)在凳厢,我們已經(jīng)獲得了一個新線索账胧,有一個叫做“可迭代的”概念。
首先先紫,我們從報錯來分析治泥,好像之所以1234不可以for循環(huán),是因為它不可迭代遮精。那么如果“可迭代”居夹,就應(yīng)該可以被for循環(huán)了败潦。
這個我們知道呀,字符串准脂、列表劫扒、元組、字典狸膏、集合都可以被for循環(huán)沟饥,說明他們都是可迭代的。
我們怎么來證明這一點呢湾戳?
from collections import Iterable
l = [1,2,3,4]
t = (1,2,3,4)
d = {1:2,3:4}
s = {1,2,3,4}
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))
結(jié)合我們使用for循環(huán)取值的現(xiàn)象贤旷,再從字面上理解一下,其實迭代就是我們剛剛說的砾脑,可以將某個數(shù)據(jù)集內(nèi)的數(shù)據(jù)“一個挨著一個的取出來”幼驶,就叫做迭代。
二韧衣、迭代器(iterator)
從第一點可以看到我們常用的字符串盅藻、列表和字典都是可迭代對象,但是可迭代對象除了那些汹族,還包括了迭代器
結(jié)論:
可迭代對象包含迭代器
定義可迭代對象萧求,必須實現(xiàn)iter()方法;定義迭代器顶瞒,必須實現(xiàn)iter()和next()方法夸政。
下面以列表舉個栗子,列表是可迭代對象榴徐,所以可以用iter()方法守问,查看返回值,發(fā)現(xiàn)該返回值也是可迭代對象坑资,也就是說列表是可迭代對象耗帕,列表執(zhí)行完iter()方法后也是可迭代對象,那么可以猜得到那個返回值應(yīng)該就是迭代器了袱贮,然后執(zhí)行next()方法果然可以從里面取值
from collections import Iterable
l = [1,2,3,4]
l_iter = l.__iter__()
print(type(l_iter)) #<class 'list_iterator'>
print(isinstance(l,Iterable)) #true
print(isinstance(l_iter,Iterable)) #true
item = l_iter.__next__()
print(item) #1
item = l_iter.__next__()
print(item) #2
item = l_iter.__next__()
print(item) #3
item = l_iter.__next__()
print(item) #4
item = l_iter.__next__()
print(item) #StopIteration
三仿便、生成器(generator)
生成器其實是一種特殊的迭代器,不過這種迭代器更加優(yōu)雅攒巍。它不需要再像上面的類一樣寫__iter__()
和__next__()
方法了嗽仪,只需要一個yiled
關(guān)鍵字。 生成器一定是迭代器(反之不成立)柒莉,因此任何生成器也是以一種懶加載的模式生成值闻坚。用生成器來實現(xiàn)斐波那契數(shù)列的例子是:
def fib(max):
n, prev, curr = 0, 0, 1
while n<max:
yield curr
prev, curr = curr, curr + prev
n += 1
F = fib(10)
# print(type(F)) <class 'generator'>
#第一種取值方式
x = next(F)
print(x)
x = next(F)
print(x)
x = next(F)
print(x)
y = F.__next__()
print(y)
y = F.__next__()
print(y)
y = F.__next__()
print(y)
#第二種取值方式
for _ in F:
print(_)
上面的命令執(zhí)行后,生成1兢孝、1窿凤、2仅偎、......、55的一共10個值雳殊,第一種取值方式生成了六個值橘沥,然后就好像固定住了,第二種方式從第七個值開始取相种,懶加載應(yīng)該就是這個意思了威恼。
生成器特殊的地方在于函數(shù)體中沒有return
關(guān)鍵字品姓,函數(shù)的返回值是一個生成器對象寝并。當執(zhí)行F = fib(10)
返回的是一個生成器對象,此時函數(shù)體中的代碼并不會執(zhí)行腹备,只有顯示或隱示地調(diào)用next或者for循環(huán)的時候才會真正執(zhí)行里面的代碼衬潦。
四、生成器表達式(generator expression)
生成器表達式是列表推倒式的生成器版本植酥,看起來像列表推導式镀岛,但是它返回的是一個生成器對象而不是列表對象。
a = (x for x in range(10))
print(a)
以及
def fib(n):
m, a, b = 0, 0, 1
while m < n:
yield b
a, b = b, a+b
m += 1
a = (x for x in fib(10))
print(a)