1. 程式人生 > >what's the python之可叠代對象、叠代器與生成器(附面試題)

what's the python之可叠代對象、叠代器與生成器(附面試題)

urn for循環 生成器 出現 擁有 移動 iterable 文本 協議

可叠代對象

字符串、列表、元祖、集合、字典都是可叠代的,數字是不可叠代的。(可以用for循環遍歷取出內部元素的就是可叠代的)

如何查看一個變量是否為可叠代:

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)) #結果為True就是可叠代,False就是不可叠代

可以被叠代要滿足的要求就叫做可叠代協議。可叠代協議的定義就是內部實現了__iter__方法,即可叠代對象中封裝有__iter__方法。

叠代器

叠代器:用變量調__iter__後就可以生成一個叠代器,叠代器遵循叠代器協議:必須擁有__iter__方法和__next__方法。

l = [1,2,3,4]
l_iter = l.__iter__()#l_iter只是一個接受的變量
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)#超出限度,報錯

上步在最後出現了報錯情況,為了使程序不報錯,可以在取完了的最後將其終止掉:

l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    
try: item = l_iter.__next__() print(item) except StopIteration: break

生成器

生成器:(本質就是一個叠代器,不過是由程序員寫出來的才叫生成器,內置的就叫叠代器)

  1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行,惰性。

  2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表

簡易生成器:

import time
def func():
    a = 1
    print(現在定義了a變量)
    yield a
    b = 2
    print(現在又定義了b變量)
    yield b

g1 = func()
print(g1 : ,g1)       #打印g1可以發現g1就是一個生成器
print(-*20)   #我是華麗的分割線
print(next(g1))
time.sleep(1)   #sleep一秒看清執行過程
print(next(g1))#每print一次next才會出來一個yield的值,不然就掛在上一個yield上不繼續執行

生成器有什麽好處呢?就是不會一下子在內存中生成太多數據,只有在你要的時候才會給你你要的數據

生成器應用的幾個小栗子:

有關衣服訂單:

技術分享圖片
def produce():
    """生產衣服"""
    for i in range(2000000):
        yield "生產了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break

#到這裏我們找工廠拿了8件衣服,我一共讓我的生產函數(也就是produce生成器函數)生產2000000件衣服。
#剩下的還有很多衣服,我們可以一直拿,也可以放著等想拿的時候再拿
View Code

生成器監聽文件輸入的栗子:

技術分享圖片
import time

def tail(filename):
    f = open(filename)
    f.seek(0, 2) #從文件末尾算起
    while True:
        line = f.readline()  # 讀取文件中新的文本行
        if not line:
            time.sleep(0.1)
            continue
        yield line

tail_g = tail(tmp)
for line in tail_g:
    print(line)
View Code

計算移動平均值(類似於年化收益):

技術分享圖片
def averager():
    total = 0
    day = 0
    average = 0
    while True:
        term = yield average
        total += term
        day += 1
        average = total/day


g_avg = averager()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(12))
print(g_avg.send(13))
View Code

yield from可以在實行for循環的效果的同時將代碼變少:

def gen1():
    for c in AB:
        yield c
    for i in range(3):
        yield i

print(list(gen1()))#[‘A‘,‘B‘,1,2,3]




#簡化版本
def gen2():
    yield from AB
    yield from range(3)

print(list(gen2()))#[‘A‘,‘B‘,1,2,3]

列表推導式和生成器表達式:(這裏用一個小故事講解知識點)

技術分享圖片
#為了彰顯高富帥本質,一口氣買了十個茶葉蛋,將他們依次排開並編號,拍照發到朋友圈

egg_list=[茶葉蛋%s %i for i in range(10)] #列表解析

#可是這十個茶葉蛋一口氣吃不完啊,要吃也就是一個一個吃,那麽就吃一個拍一個照吧

eat=(茶葉蛋%s %i for i in range(10))#生成器表達式
print(eat)
print(next(eat)) #next本質就是調用__next__
print(eat.__next__())
print(next(eat))
高富帥與茶葉蛋

總結:

1.把列表解析的[]換成()得到的就是生成器表達式

2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存

3.Python使用叠代器協議,讓for循環變得更加通用。大部分內置函數,也是使用叠代器協議訪問對象的。

附:與生成器相關的面試題:

技術分享圖片
def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
g2=(i for i in g1)

print(list(g1))#[0,1,2,3]
print(list(g2))#[]
面試題1 技術分享圖片
def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,10]:
    g=(add(n,i) for i in g)

print(list(g))#[20,21,22,23]
面試題2

what's the python之可叠代對象、叠代器與生成器(附面試題)