python之路——迭代器與生成器

要了解for循環是怎么回事兒,咱們還是要從代碼的角度出發。

首先,我們對一個列表進行for循環。

for i in [1,2,3,4]:  print(i)

上面這段代碼肯定是沒有問題的,但是我們換一種情況,來循環一個數字1234試試

復制代碼
for i in 1234print(i) 結果:
Traceback (most recent call last):File "test.py", line 4, in <module>for i in 1234:
TypeError: 'int' object is not iterable
復制代碼

iterable:是可迭代的意思。

?

首先,我們從報錯來分析,好像之所以1234不可以for循環,是因為它不可迭代。那么如果“可迭代”,就應該可以被for循環了。

這個我們知道呀,字符串、列表、元組、字典、集合都可以被for循環,說明他們都是可迭代的

我們怎么來證明這一點呢?

復制代碼
from collections import Iterablel = [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))
復制代碼

結合我們使用for循環取值的現象,再從字面上理解一下,其實迭代就是我們剛剛說的,可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做迭代

可迭代協議

我們現在是從結果分析原因,能被for循環的就是“可迭代的”,但是如果正著想,for怎么知道誰是可迭代的呢?

假如我們自己寫了一個數據類型,希望這個數據類型里的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。

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

接下來我們就來驗證一下:

print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))
復制代碼
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
復制代碼

總結一下我們現在所知道的:可以被for循環的都是可迭代的,要想可迭代,內部必須有一個__iter__方法。

接著分析,__iter__方法做了什么事情呢?

print([1,2].__iter__())結果
<list_iterator object at 0x1024784a8>

執行了list([1,2])的__iter__方法,我們好像得到了一個list_iterator,現在我們又得到了一個新名詞——iterator。

iterator是一個計算機中的專屬名詞,叫做迭代器。?

?

生成器:

為什么要有for循環

基于上面講的列表這一大堆遍歷方式,聰明的你立馬看除了端倪,于是你不知死活大聲喊道,你這不逗我玩呢么,有了下標的訪問方式,我可以這樣遍歷一個列表啊

復制代碼
l=[1,2,3]index=0
while index < len(l):print(l[index])index+=1#要毛線for循環,要毛線可迭代,要毛線迭代器
復制代碼

沒錯,序列類型字符串,列表,元組都有下標,你用上述的方式訪問,perfect!但是你可曾想過非序列類型像字典,集合,文件對象的感受,所以嘛,年輕人,for循環就是基于迭代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象的__iter__方法將其轉換成一個迭代器,然后使用迭代器協議去實現循環訪問,這樣所有的對象就都可以通過for循環來遍歷了,而且你看到的效果也確實如此,這就是無所不能的for循環,覺悟吧,年輕人

生成器

返回頂部

初識生成器

我們知道的迭代器有兩種:一種是調用方法直接返回的,一種是可迭代對象通過執行iter方法得到的,迭代器有的好處是可以節省內存。

如果在某些情況下,我們也需要節省內存,就只能自己寫。我們自己寫的這個能實現迭代器功能的東西就叫生成器。

?

Python中提供的生成器:

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

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

?

生成器Generator:

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

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

?

生成器函數

一個包含yield關鍵字的函數就是一個生成器函數。yield可以為我們從函數中返回值,但是yield又不同于return,return的執行意味著程序的結束,調用生成器函數不會得到返回的具體的值,而是得到一個可迭代的對象。每一次獲取這個可迭代對象的值,就能推動函數的執行,獲取新的返回值。直到函數執行結束。

復制代碼
import time
def genrator_fun1():a = 1print('現在定義了a變量')yield ab = 2print('現在又定義了b變量')yield bg1 = genrator_fun1()
print('g1 : ',g1)       #打印g1可以發現g1就是一個生成器
print('-'*20)   #我是華麗的分割線
print(next(g1))
time.sleep(1)   #sleep一秒看清執行過程
print(next(g1))
復制代碼

?

生成器有什么好處呢?就是不會一下子在內存中生成太多數據

假如我想讓工廠給學生做校服,生產2000000件衣服,我和工廠一說,工廠應該是先答應下來,然后再去生產,我可以一件一件的要,也可以根據學生一批一批的找工廠拿。
而不能是一說要生產2000000件衣服,工廠就先去做生產2000000件衣服,等回來做好了,學生都畢業了。。。

復制代碼
#初識生成器二def produce():"""生產衣服"""for i in range(2000000):yield "生產了第%s件衣服"%iproduct_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 +=1if num == 5:break#到這里我們找工廠拿了8件衣服,我一共讓我的生產函數(也就是produce生成器函數)生產2000000件衣服。
#剩下的還有很多衣服,我們可以一直拿,也可以放著等想拿的時候再拿
復制代碼

?

更多應用

復制代碼
import timedef tail(filename):f = open(filename)f.seek(0, 2) #從文件末尾算起while True:line = f.readline()  # 讀取文件中新的文本行if not line:time.sleep(0.1)continueyield linetail_g = tail('tmp')
for line in tail_g:print(line)
復制代碼

send

復制代碼
def generator():print(123)content = yield 1print('=======',content)print(456)yield2g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')   #send的效果和next一樣
print('***',ret)#send 獲取下一個值的效果和next基本一致
#只是在獲取下一個值的時候,給上一yield的位置傳遞一個數據
#使用send的注意事項# 第一次使用生成器的時候 是用next獲取下一個值# 最后一個yield不能接受外部的值
復制代碼
復制代碼
def averager():total = 0.0count = 0average = Nonewhile True:term = yield averagetotal += termcount += 1average = total/countg_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 greturn inner@init
def averager():total = 0.0count = 0average = Nonewhile True:term = yield averagetotal += termcount += 1average = total/countg_avg = averager()
# next(g_avg)   在裝飾器中執行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
復制代碼

yield from

復制代碼
def gen1():for c in 'AB':yield cfor i in range(3):yield iprint(list(gen1()))def gen2():yield from 'AB'yield from range(3)print(list(gen2()))
復制代碼

?

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

?峰哥與alex的故事

總結:

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

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

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

sum(x ** 2 for x in range(4))

而不用多此一舉的先構造一個列表:

sum([x ** 2 for x in range(4)]) 

?

更多精彩請見——迭代器生成器專題:http://www.cnblogs.com/Eva-J/articles/7276796.html

本章小結

可迭代對象:

  擁有__iter__方法

  特點:惰性運算

  例如:range(),str,list,tuple,dict,set

迭代器Iterator:

  擁有__iter__方法和__next__方法

  例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o

生成器Generator:

  本質:迭代器,所以擁有__iter__方法和__next__方法

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

使用生成器的優點:

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

?

?列表解析式和生成器表達式

?

2.提高代碼可讀性

?

生成器相關的面試題

生成器在編程中發生了很多的作用,善用生成器可以幫助我們解決很多復雜的問題

除此之外,生成器也是面試題中的重點,在完成一些功能之外,人們也想出了很多魔性的面試題。
接下來我們就來看一看~

?面試題1
?面試題2
?tail&grep

轉載于:https://www.cnblogs.com/zsdbk/p/9387781.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/397377.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/397377.shtml
英文地址,請注明出處:http://en.pswp.cn/news/397377.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTML頁面顯示透視效果,html – CSS – 對背景圖像的“敲除”/透視效果

我認為這里的想法是圖像必須足夠大,以覆蓋網頁或至少父母div ..然后,您可以將圖像應用于容器和’inner’div的背景.覆蓋可以通過偽元素而不是單獨的div來實現.修訂結構 –.bck {position: relative;height: 800px;width: 100%;background:url(http://webneel.com/wallpaper/sit…

DFS分布式文件系統--管理篇

DFS分布式文件系統--管理篇參考文檔&#xff1a;淺談DFS分布式文件系統DFS 命名空間 和 DFS 復制概述續DFS分布式文件系統--基礎篇DFS分布式文件系統--部署篇添加命名空間服務器&#xff08;添加第二臺命名空間服務器 NameSrv02)成功后如下圖&#xff1a;“從顯示區域隱藏命名空…

Linux 0-1 修改主機名及IP地址

1.修改主機名 hostname 查看主機名 vi /etc/sysconfig/network 修改hostname主機名 vi /etc/hosts 修改127.0.1 主機名 service network restart #/etc/hosts 在域名解析時優先于DNS服務器2.IP地址 ifconfig 查看目前網絡卡信息 cd /etc/sysconfig/network-scripts ls查看…

html漸變顏色代碼表,漸變顏色代碼表

漸變顏色代碼表2020-12-24素材&#xff1a;網絡 編輯&#xff1a;唔爾灬#000000#2F0000#600030#460046#28004D#272727#4D0000#820041#5E005E#3A006F#3C3C3C#600000#9F0050#750075#4B0091#4F4F4F#750000#BF0060#930093#5B00AE#5B5B5B#930000#D9006C#AE00AE#6F00D2#6C6C6C#AE0000…

js貪心算法---背包問題

/** param {Object} capacity 背包容量 6* param {Object} weights 物品重量 [2,3,4]* param {Object} values 物品價值 [3,4,5]*///貪心算法&#xff0c;只能算&#xff0c;可以分割的物品&#xff0c;如果不能分割物品&#xff0c;只能得到近似解&#xff0c;不分割物品&…

Spring利用JDBCTemplate實現批量插入和返回id

1、先介紹一下java.sql.Connection接口提供的三個在執行插入語句后可取的自動生成的主鍵的方法&#xff1a; //第一個是 PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException; 其中autoGenerateKeys 有兩個可選值&#xff1a;Stat…

jsp壓縮html,使用HtmlCompressor壓縮JSP編譯的Html代碼

HtmlCompressor 能夠刪除多余的HTML代碼。它提供多種方法&#xff1a;刪除無用的空行、刪除注釋以及刪除無用的表格等等&#xff0c;簡單而有效。在Java代碼中可以這樣使用&#xff1a;String html getHtml(); //需要處理的Html代碼HtmlCompressor compressor new HtmlCompre…

LVS負載均衡(3)——LVS工作模式與工作原理

LVS介紹及工作原理1. LVS 介紹LVS,Linux Virtual Server 的簡寫&#xff0c;意即 Linux 虛擬服務器&#xff0c;是一個虛擬的服務器集群系統&#xff0c;可以在 UNIX/Linux 平臺下實現負載均衡集群功能。文章&#xff1a;LVS項目介紹LVS集群體系結構LVS集群的IP負載均衡技術LVS…

保留凸性的方式:一個凸函數在一個隨機變量上的期望仍然是凸函數

設函數 gg 是實數范圍內的一個凸函數&#xff0c;DD 是一個隨機變量&#xff0c; 那么函數 GEDg(y?D)GEDg(y?D) 仍然是一個凸函數。 證明&#xff1a;記 θθθθ, yy 與 yy 是任意兩個數 ≥θG(y)θG(y)θEDg(y?D)θEDg(y?D)ED[θg(y?D)θ(gy?D)]ED[g(θyθy?D)]G(θyθ…

MyBatis入門(二)---一對一,一對多

一、創建數據庫表 1.1、創建數據表同時插入數據 /* SQLyog Enterprise v12.09 (64 bit) MySQL - 5.6.27-log : Database - mybatis ********************************************************************* *//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE*/;/*!40014 SE…

零基礎學Java的10個方法

2019獨角獸企業重金招聘Python工程師標準>>> 版權聲明&#xff1a;本文為北京尚學堂原創文章&#xff0c;未經允許不得轉載。? 零基礎學Java只要方法得當&#xff0c;依然有機會學習好Java編程。 但作為初學者可以通過制定一些合理清晰的學習計劃。 在幫你屢清楚思…

html 轉換為cshtml,使用Html而不是csHtml

我想使用純HTML頁面而不是使用MVC .net的cshtml . 但是當我通過右鍵單擊索引添加視圖時&#xff0c;我只能看到兩個選項 .public class HomeController : Controller{//// GET: /Home/public ActionResult Index(){return View();}}Cshtml(剃刀)Aspx論壇但仍無濟于事 . 我仍然沒…

scp windows 和 linux 遠程復制 (雙向)

一下命令在cmd中 從w -> l : scp D:\a.txt root192.168.2.113:/home/a 從l -> w: scp root192.168.2.113:/home/aaa d:/b.txt 按說在Linux中也可以&#xff0c;但是不知道怎么的只有在winodws上行&#xff0c;在linux上就會報 ssh: connect to host 192.168.2.157 port 2…

北京尚學堂|程序員的智慧

2019獨角獸企業重金招聘Python工程師標準>>> 版權聲明&#xff1a;本文為北京尚學堂原創文章&#xff0c;未經允許不得轉載。 編程是一種創造性的工作&#xff0c;是一門藝術。精通任何一門藝術&#xff0c;都需要很多的練習和領悟&#xff0c;所以這里提出的“智慧…

翼城中學2021高考成績查詢入口,2021年臨汾中考分數線查詢(4)

臨汾2021年中考分數線查詢 2021臨汾中考錄取分數線 19年臨汾中考各校錄取分數線 臨汾各高中錄取分數線 臨汾2021中考錄取線查詢 中考信息網提供2021臨汾中考分數線查詢信息。臨汾中考錄取分數線預計7月初公布&#xff0c;屆時考生可登陸臨汾招生考試網官網查看分數線情況。2…

JSP EL表達式 param、paramValues的使用

JSP EL表達式 param、paramValues的使用&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath request.getScheme() "://" request…

配置Tomcat使用HTTP/2

轉自&#xff1a; https://zhuanlan.zhihu.com/p/21349186 前情提要&#xff1a; Tomcat高效響應的秘密(一) Sendfile與Gzip Tomcat高效響應的秘密(二) keep alive 前面高效響應的兩篇&#xff0c;我們分析了Sendfile的特性以及HTTP1.1的keep-alive特性&#xff0c;基于這些功…

asp.net razor html,從控制臺應用程序中的ASP.NET Razor模板生成HTML的當前最佳解決方案是什么?...

ServiceStack是用于呈現Razor視圖頁面的另一個選項。 盡管它已針對集成到ASP.NET或HttpListener Web Host中進行了優化(并提供了用于在目錄中自動發現和注冊視圖頁面&#xff0c;即時重新編譯修改后的頁面等的API)&#xff0c;但它還支持靜態生成視圖頁面 &#xff1a;var razo…

通過NSNotification來監聽鍵盤彈出和彈回

在通知中心建立一個廣播來監聽鍵盤的彈出和彈回&#xff0c;在監聽事件中加入觸發事件的一些操作。 [[NSNotificationCenter defaultCenter]addObserver:self selector:selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];[[NSNotificatio…

Xcode緩存數據清除

1. 移除 APP 打包的ipa歷史版本(Archives) 不可恢復&#xff0c;就是你打的包&#xff0c;如果需要dysm文件&#xff0c;及時備份 路徑&#xff1a;~/Library/Developer/Xcode/Archives 2. 移除對舊設備的支持 可重新生成&#xff1b;再連接舊設備調試時&#xff0c;會重新自動…