python怎么由列表生成m*n的矩阵_Python进阶系列:Python遍历的秘密
前言
可迭代對象,迭代器,生成器,相信許多學(xué)習(xí)Python的小伙伴或多或少都聽說過,但你真的知道他們的區(qū)別嗎?真的知道為什么需要這些概念嗎?
本文帶你深入了解一系列相關(guān)機制,不僅告訴你概念,還告訴你為什么需要這些概念,讓你可以舉一反三。
本文重點
- Python在for遍歷時做了什么?
- 為什么需要迭代器?
- 生成器為什么不能重復(fù)使用?
- Python的動態(tài)協(xié)議,不一樣的迭代實現(xiàn)。
本文字數(shù)2000+,不適合初學(xué)者,閱讀本文需要你有以下Python基礎(chǔ)知識:
- 認識列表(list)
- for循環(huán)等基本語法。
- 自定義類型,方法。
原創(chuàng)不容易,請點擊右上方關(guān)注按鈕,多多支持~
for循環(huán)沒有你想象中的那么簡單
能夠看到這里的小伙伴必定已經(jīng)很熟悉for循環(huán),但你可能不知道Python在背后為你做了許多事情。
用一個簡單例子來說明一下,當(dāng)前有一個列表,里面裝著4個數(shù)字,我們需要把數(shù)字逐一打印出來。
如下圖,分別用兩種方式實現(xiàn):
- 行5-行7,第一種方式,通過索引訪問列表
- 行10-行11,直接通過for遍歷。
- 大家有想過嗎?為什么第二種方法,不需要一個變量 i 來記錄當(dāng)前讀取位置呢。
答案是,不管什么方式,其實都需要在遍歷過程保持一個狀態(tài)值,以表示現(xiàn)在遍歷到哪個元素。
但是為什么我們平時使用的for循環(huán)卻不需要呢?
因為Python在for循環(huán)之前靜悄悄地做了以下事情:
- 行10,這里是遍歷的開始。但別以為 Python 是直接向 nums 拿數(shù)值。
- 在遍歷開始之前,Python 會先問 nums 拿一個叫迭代器的東西。
- 然后每次都問這個迭代器拿數(shù)值,然后把數(shù)值賦給變量 n 。
我們來看看示意圖:
- Python 通過 iter(nums) 拿到一個迭代器,然后才開始遍歷。
- 第一次遍歷時,會問迭代器拿一個元素,然后把元素賦值給變量 n 。
- 整個過程,iter 執(zhí)行了一次,next 執(zhí)行了4次。
- 之前說的狀態(tài)值 i ,其實就保存在迭代器中。
- 以上的步驟從代碼上是看不到的。
可以看到,迭代器就是為了保存遍歷狀態(tài)而設(shè)定的。
迭代器的由來
你可能會疑惑,為什么多此一舉,非要弄一個所謂的迭代器出來?
可以把狀態(tài)值 i ,保存在列表對象中啊。
答案是,因為在嵌套for遍歷的時候,需要兩個for的狀態(tài)值 i 是獨立分開的。
看下圖:
- 如果狀態(tài)值 i 直接保存在列表對象中,那么這里的嵌套遍歷就亂套了。
- 可見,這里 Python 會為我們創(chuàng)建了2個獨立的迭代器,獨立維護了2個狀態(tài)值 i 。
上面例子中,列表 nums 稱為"可迭代對象"
說白了,迭代器就是用于維護一個遍歷過程中的狀態(tài)數(shù)據(jù)。
不是任何對象都有迭代器的
以上就是迭代器的由來,但似乎目前為止我們都沒看到迭代器是個啥樣。
通過下圖的代碼,來看看迭代器吧:
- 行22,通過 iter 方法從列表 nums 中獲取一個迭代器。
- 行26,通過 next 方法從迭代器 tor 中獲取一個值。
- 行24-行29,就是整個遍歷的過程。
- 行28,當(dāng)列表中的值都被取出來后,在行26 中再次問 tor 獲取值的時候,就會出現(xiàn) StopIteration 的錯誤。
重點歸納一下:
- 如果一個類正確實現(xiàn)了 __iter__ 方法,那么這個對象叫"可迭代對象"
- 可以通過 iter 方法從可迭代對象身上獲取一個迭代器。
- 迭代器是一個正確實現(xiàn) __next__ 方法的對象。
- 迭代器的狀態(tài)是無法重置,只能向前。一旦遍歷完畢,則無法再次使用。
- 例子中, nums 列表是一個可迭代對象。
題外話:實際上迭代器還正確實現(xiàn)了 __iter__ 方法,不過這個方法只是簡單地返回迭代器自身。
生成器其實就是一種迭代器
所謂的生成器,指定的是一種不斷生成輸出東西的事物,同樣地可以通過 next 方法從生成器上獲取輸出。
是不是與迭代器的概念不謀而合?那又是為什么弄這樣的一個概念出來?
生成器的特點
- 生成器的數(shù)據(jù)來源與迭代器不一樣。
- 行48-行51,生成器的來源不一定是可迭代對象,他可以是一個不斷輸出值的函數(shù)。
- 行45,因此,生成器有著迭代器一樣的性質(zhì)。不能重復(fù)使用。
真的需要 __iter__ 才是可迭代對象嗎?
Python中的協(xié)議不像Java或C#這么嚴格,當(dāng)一個對象實現(xiàn)了 __getitem__ 方法,并且可以從0索引開始訪問元素時,同樣也可以迭代他。
如下:
- 行62,實現(xiàn)了 __getitem__ 方法,就是讓這個對象可以通過諸如 mn[0] 這樣的方式去獲取元素。
- Python 在 for 循環(huán)時,發(fā)現(xiàn) MyNums 雖然沒實現(xiàn) __iter__ 方法,但有 __getitem__ 方法,那么自然可以通過維護一個狀態(tài)索引值 i ,不斷調(diào)用 __getitem__ 方法實現(xiàn)遍歷的效果。
小結(jié)
- 我們平時經(jīng)常使用的列表,元組,字典等集合,他們都是可迭代對象。
- 迭代器在 Python 中被定義為"只讀向前",一旦使用完畢,則不能再次使用。
- 生成器就是一種迭代器,因此擁有迭代器同樣的性質(zhì)與限制。
- 當(dāng)自定義類型需要可迭代時,實現(xiàn) __iter__ 方法。
- 如果沒有實現(xiàn) __iter__ 方法,那么實現(xiàn) __getitem__ 方法也是可以支持迭代。
如果覺得本文對你有所幫助,記得關(guān)注、評論、轉(zhuǎn)發(fā)、收藏噢~ 私信我"python",即可獲得按水平領(lǐng)域分類好的Python資料,還會不定期更新有用的Python技巧。
總結(jié)
以上是生活随笔為你收集整理的python怎么由列表生成m*n的矩阵_Python进阶系列:Python遍历的秘密的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bp神经网络pid控制_文章推荐 | B
- 下一篇: mysql空表_MySQL中两种快速创建