1. 程式人生 > >Python-19-叠代器和生成器

Python-19-叠代器和生成器

+= on() 保留 內置函數 異常 iter 器) rate pri

一、叠代器

叠代器協議:
1.叠代器協議是指:對象必須提供一個next方法,執行該方法要麽返回叠代中的下一項,
要麽就引起一個StopIteration異常,以終止叠代 (只能往後走不能往前退)#
2.可叠代對象:實現了叠代器協議的對象(如何實現:對象內部定義一個__iter__()方法)
3.協議是一種約定,可叠代對象實現了叠代器協議,python的內部工具(如for循環,sum,min,max函數等)
使用叠代器協議訪問對象

for 循環機制:
1、for循環的本質:循環所有對象,全都是使用叠代器協議。
2、for循環就是基於叠代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象
的__iter__方法將其轉換成一個叠代器,然後使用叠代器協議去實現循環訪問,這樣所有的對象就都
可以通過for循環來遍歷了,
3、列表,字符串,元組,字典,集合,文件對象等本質上來說都不是可叠代對象,在使用for循環的時候
內部是先調用他們內部的_iter_方法,使他們變成了可叠代對象,然後在使用可叠代對象的_next_方
法依次循環元素,當元素循環完時,會觸發StopIteration異常,for循環會捕捉到這種異常,終止叠代
4、訪問方式:下標方式訪問、叠代器協議訪問、for循環訪問
# 1)下標訪問方式--索引
li = [1,2,3,4]
print(li[0])                # 下標訪問(索引)

index = 0
while index < len(li):
    print(li[index])
    index += 1


# 2)叠代器協議訪問
li = [1,2,3,4]
f = li.__iter__()           # 第一步,先通過內部的_iter_方法,先把對象變成可叠代對象
print(f.__next__())         # 對可叠代對象用_next_方法取值
print(f.__next__())
print(f.__next__()) print(f.__next__()) print(f.__next__()) # StopIteration,超出邊界會報錯 print(next(f)) # next(f) 就是 f.__next__() print(next(f)) # 3)for循環訪問 li = [1,2,3,4] for i in li: # li_iter = li._iter_() print(i) # li_iter._next_ # 4)用while去模擬for循環做的事情
li = [1,2,3,4] diedai_l=li.__iter__() while True: try: print(diedai_l.__next__()) except StopIteration: print(叠代完畢了,循環終止了) break

二、生成器

生成器類似於一種數據類型,這種數據類型自動實現了叠代器協議(其他的數據類型需要調用自
己內置的__iter__方法),所以生成器就是可叠代對象

生成器分類及在python中的表現形式:(Python有兩種不同的方式提供生成器)
1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次
返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建
一個結果列表,按需取出對象

為何使用生成器之生成器的優點:
Python使用生成器對延遲操作提供了支持。所謂延遲操作,是指在需要的時候才產生結果,而不是立
即產生結果。這也是生成器的主要好處。

########## 生成器小結 ###########
1、是可叠代對象
2、實現了延長計算、升內存
3、生成器本質和其他的數據類型一樣,都是實現了叠代器協議,只不過生成器附加了一個延遲計算省內存的好處,
其余的同叠代對象沒有這點好處。
########## 生成器小結 ###########

------------------ 1、生成器表達式 ------------------
# 1)三元表達式:
f = result = 值1 if 條件 else 值2      # True 輸出值1;False 輸出值2.
name = "newmet"
f = "TRUE_1" if name == "newmet" else "FALSE_1"
print(f)

# 2)列表解析:
# s = [三元表達式],列表解析生成的是一個真實存在於內存中的列表,對於比較大的列表,比較耗內存空間
count = [x for x in range(10)]  # 列表解析
l = ["蘋果%s" % i for i in range(10)]  # 列表解析
print(l)  # 結果:[‘蘋果0‘, ‘蘋果1‘, ‘蘋果2‘, ‘蘋果3‘, ‘蘋果4‘, ‘蘋果5‘, ‘蘋果6‘, ‘蘋果7‘, ‘蘋果8‘, ‘蘋果9‘]
l1 = ["蘋果%s" % i for i in range(10) if i > 5]
print(l1)  # 結果:[‘蘋果6‘, ‘蘋果7‘, ‘蘋果8‘, ‘蘋果9‘]

# 3)生成器表達式---[] 變成 ()
# 列表解析
sum([i for i in range(1000000)])  # 內存占用大,機器容易卡死
# 生成器表達式
sum(i for i in range(1000000))    # 幾乎不占內存
# sum函數是Python的內置函數,該函數使用叠代器協議訪問對象,而生成器實現了叠代器協議,不用多此一舉先生成列表

l2 = ("蘋果%s" % i for i in range(10))  # [] 變成 () 生成器表達式!!!!!!
print(l2)  # 結果:<generator object <genexpr> at 0x00000000037F9930> 內存地址
print(l2.__next__())  # 結果:蘋果0
print(l2.__next__())  # 結果:蘋果1
print(next(l2))  # 結果:蘋果2
------------------ 2、生成器函數 ------------------
def test():
    yield 1         # 相當於return,不同於return,yield可以返回多個值
    yield 2
    yield 3

res = test()
print(res)             # 結果:<generator object test at 0x00000000037F9930> 內存地址
print(res.__next__())  # 結果:1   保留當前執行狀態,下次執行從上次狀態處繼續往下執行
print(res.__next__())  # 結果:2
print(res.__next__())  # 結果:3   執行只能一直往前走,不能往後,只能執行一次,執行完繼續執行會觸發StopIteration

# 例1:母雞下蛋
def xiadan():
    for i in range(10):
        yield "雞蛋%s"%i
f = xiadan()
# for j in f:
#     print(j)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())

# 例2:人口普查
def get_population():
    with open("人口普查", "r", encoding="utf-8") as f:
        for i in f:
            yield i


g = get_population()
all_g = sum(eval(i)[population] for i in g)
print(all_g)

# 例3:吃包子

# 生產包子函數:
import time
def producer():
    ret=[]
    for i in range(100):
        time.sleep(0.1)
        ret.append("包子%s" %i)
    return ret
# 吃包子函數:
def consumer(res):
    for index,baozi in enumerate(res):
        time.sleep(0.1)
        print("第%s個人,吃了%s" %(index,baozi))
res = producer()
consumer(res)
# 這樣的生產與消費是:先生產完包子,再去賣,效率太低,不符合實際需求。

# 偽並發
# send():可對yield函數傳參數,參數會賦值給yield函數前的變量,通過send()可實現偽並發功能!!!!!!

import time #導入時間模塊
def consumer(name):
    print("我是%s,我準備吃包子了"%name)
    while True:
        baozi = yield
        time.sleep(1)
        print("我是%s,我把包子%s吃掉了"%(name,baozi))
def producer(x):
    user_name = consumer(x)
    user_name.__next__()
    for i in range(100):
        time.sleep(1)
        user_name.send(i)#將i賦值給consumer()函數中yield前面的包子,下次執行時從此往後執行
use_name = input("歡迎您!請問怎麽稱呼您:")
print("好的,麻煩請稍等!包子馬上就給您端上來")
producer(use_name)
三、生產者消費者模型
import time
# 消費者--程序
def consumer(name):
    print("我是[%s],我準備吃包子了;" %name)
    while True:
        baozi = yield
        time.sleep(1)
        print("%s 很開心的把[%s]吃掉了。" %(name,baozi))
# 生產者--程序
def producer():
    v1=consumer("newmet1")
    v2=consumer("newmet2")
    v1.__next__()
    v2.__next__()
    for i in range(10):
        time.sleep(1)
        v1.send("包子%s" %i)          # 將i賦值給producer()函數中yield前面的包子,下次執行時從此往後執行
        v2.send("包子%s" %i)
producer()
 

Python-19-叠代器和生成器