當前位置:
首頁 > 知識 > python函數(5):迭代器和生成器

python函數(5):迭代器和生成器

迭代器和生成器是函數中的一大重點,務必掌握,何為迭代?何為迭代器?

預習:

1、處理文件,用戶指定要查找的文件和內容,將文件中包含要查找內容的每一行都輸出到屏幕(使用生成器)

2、批量處理文件,用戶指定要查找的目錄和內容,將本層目錄下所有文件中包含要查找內容的每一行都輸出到屏幕

一、迭代器

for i in 50:
print(i)
#運行結果:
# Traceback (most recent call last):
# File "G:/python/python代碼/八月/day2 迭代器生成器/3迭代器.py", line 8, in <module>
# for i in 50:
# TypeError: "int" object is not iterable

報錯:

TypeError: "int" object is not iterable

類型報錯:"int"對象是不可迭代的 何為迭代?

iterable:可迭代的;迭代的;

可迭代的:從上面代碼可以簡單分析出能被for循環取值的就是可迭代,那麼我們就可以初步總結出可迭代的類型:str、list、tuple、set、dict

可迭代的 ——對應的標誌 擁有__iter__方法

print("__iter__" in dir([1,2,3])) #判斷一個變數是不是一個可迭代的

可迭代協議

可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了__iter__方法。

二、迭代器

__iter__方法作用:

l = [1,2,3,4,5]
print(l.__iter__)
l_iterator = iter(l) #建議用iter(l)
print(set(dir(l_iterator))-set(dir(l)))
#結果:
#<list_iterator object at 0x000001FDD1B79048>
#{"__length_hint__", "__next__", "__setstate__"}

迭代器

iterator:迭代器;迭代程序

迭代器協議:必須擁有__iter__方法和__next__方法

通過iter(x)得到的結果就是一個迭代器,

x是一個可迭代的對象

在for循環中,就是在內部調用了__next__方法才能取到一個一個的值。

__next__的精髓:

l = [1,2,3,4,5]
l_iterator = iter(l)
print(l_iterator.__next__)
print(l_iterator.__next__)
print(l_iterator.__next__)
print(l_iterator.__next__)
print(l_iterator.__next__)
next(l_iterator) #==l_iterator.__next__
while True:
try:
print(next(l_iterator))
except StopIteration:
break

__next__方法的使用精髓

如果我們一直取next取到迭代器里已經沒有元素了,就會報錯(拋出一個異常StopIteration),告訴我們,列表中已經沒有有效的元素了。這個時候,我們就要使用異常處理機制來把這個異常處理掉。try_except異常處理機制只做了解,不是本章重點,會面會詳細講解。

判斷是否可迭代和迭代器的簡潔方法:

from collections import Iterable
from collections import Iterator
s = "abc"
print(isinstance(s,Iterable))
print(isinstance(s,Iterator))
print(isinstance(iter(s),Iterator))

判斷可迭代和迭代器

不管是一個迭代器還是一個可迭代對象,都可以使用for循環遍歷

迭代器出現的原因 幫你節省內存

三、生成器

迭代器大部分都是在python的內部去使用的,我們直接拿來用就行了

我們自己寫的能實現迭代器功能的東西就叫生成器。

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

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

生成器Generator:

本質:迭代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)

特點:惰性運算,開發者自定義

#生成器函數
def func:
print("aaaa")
a = 1
yield a #返回第一個值
print("bbbb")
yield 12 #返回第二個值

ret = func #拿到一個生成器
# print(ret) #<generator object func at 0x0000028AE2DA2EB8>
print(next(ret)) #取第一個值
print(next(ret)) #取第二個值
print(next(ret)) #取第三個值 會報錯 因為沒有第三個值

def make_cloth:
for i in range(2000000):
yield "第%s件衣服"%i

szq = make_cloth
print(next(szq))
print(next(szq))

print(next(szq))
for i in range(50):
print(next(szq))

生成器函數

生成器的好處:不會一下子在內存中生成太多數據

其它應用:

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)

生成器監聽文件輸入的例子

def averager:
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count

g_avg = averager
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))

計算移動平均值簡單

def init(func): #在調用被裝飾生成器函數的時候首先用next激活生成器
def inner(*args,**kwargs):
g = func(*args,**kwargs)
next(g)
return g
return inner

@init
def averager:
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count

g_avg = averager
# next(g_avg) 在裝飾器中執行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))

計算移動平均值升級_生成器激活裝飾器

def func:
# for i in "AB":
# yield i
yield from "AB" #等同於上面兩行
yield from [1,2,3]
g = func
print(next(g))
print(next(g))
print(next(g))
print(next(g))

yield from

四、列表推導式和生成器表達式

for i in range(100):
print(i*i)

l =[i*i for i in range(100)] #列表推導式
print(l)

l = [{"name":"v","age":28},{"name":"v"}]
name_list = [dic["name"] for dic in l] #列表推導式
print(name_list)

l = [{"name":"v1","age":28},{"name":"v2"}]
name_list_generator = (dic["name"] for dic in l) #生成器表達式
print(name_list_generator)
print(next(name_list_generator))
print(next(name_list_generator))

egg_list=["雞蛋%s" %i for i in range(10)] #列表推導式
print(egg_list)

laomuji = ("雞蛋%s" %i for i in range(1,11)) #生成器表達式
print(laomuji)
print(next(laomuji))
print(next(laomuji))

列表推導式和生成器表達式

使用生成器的優點:

1、延遲計算,一次返回一個結果。也就是說,它不會一次生成所有的結果,這對於大數據量處理,將會非常有用。

2、提高代碼可讀性

#列表解析
sum([i for i in range(100000000)])#內存佔用大,機器容易卡死

#生成器表達式
sum(i for i in range(100000000))#幾乎不佔內存

總結:

1、把列表解析的換成得到的就是生成器表達式

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

3、Python不但使用迭代器協議,讓for循環變得更加通用。大部分內置函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,所以,我們可以直接這樣計算一系列值的和

print(sum([1,2,3]))
print(sum(range(1,4)))
print(sum(x ** 2 for x in range(4)))
print(sum([x ** 2 for x in range(4)]))

思維導圖:

python函數(5):迭代器和生成器

預習答案:

def grep_file(filename,grep_content):
f = open(filename)
for line in f:
if grep_content in line:
yield line

g = grep_file("tmp_file","python")
for line in g:
print(line,end="")

普通青年版(1題)

def init(func):
def inner(*args,**kwargs):
g = func(*args,**kwargs)
next(g)
return g
return inner

@init #grep_file = init(grep_file)
def grep_file(grep_content,printer_g):
while True:
filename = yield
f = open(filename)
for line in f:
if grep_content in line:
printer_g.send(line)

@init ##printer = init(printer) 激活print_g
def printer:
while True:
line = yield
if line:print(line,end="")

grep_g = grep_file("python", printer)
grep_g.send("tmp_file")

妖孽青年版(1題)

import os
def getpath(filepath):
g = os.walk(filepath)
for par_dir, _, files in g:
for file in files:
yield par_dir + "" + file

# 2打開文件對象發給3
def getfile(filepaths):
for filepath in filepaths:
with open(filepath, encoding="utf-8") as file:
yield file

# 3讀取每一行發給4
def getline(files):
for file in files:
for line in file:
yield line

# 4判斷pattern發給5
def grep(lines, pattern):
for line in lines:
if pattern in line:
yield line

# 5列印文件名
def printname(strings):
for string in strings:
print(string)

filepath = r"F:CodePythonLearnPythonDay14 generator"
pattern = "jean"

printname(grep(getline(getfile(getpath(filepath))), pattern))

妖孽升級版(2題)

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

Redux源碼分析之createStore
sybase資料庫和oracle資料庫中欄位中含有換行符的解決辦法
Raft協議安全性保證

TAG:科技優家 |

您可能感興趣

靜態站點生成器:makesite.py
React代碼生成器
「python」生成器的高級應用send、close和throw方法
4 種基於 Markdown 的幻燈片生成器
pydbgen:一個資料庫隨機生成器
談談 Python 的生成器
SpringMVC,Spring,Hibernate框架自動生成器
Pelican 入門:一個 Python 靜態網站生成器
Linux密碼生成器
macOS-簡單的二維碼生成器
OpenAI「假新聞」生成器GPT-2的最簡Python實現
ES6的生成器和迭代器
Python核心編程的四大神獸:迭代器、生成器、閉包以及裝飾器
史上最強GAN圖像生成器,Inception分數提高兩倍
Python3快速入門知識點:流程式控制制、迭代器、生成器
教你用 100行Node.js 代碼,快速構建一個靜態網站生成器!
學界 | 史上最強GAN圖像生成器,Inception分數提高兩倍
「史上最強GAN圖像生成器」BigGAN的demo出了!
UI設計大咖分享Photoshop CC 生成器切片全攻略
更安全:Firefox 69 將加入隨機密碼生成器