迭代協議:Loops在Python中如何工作

2021-02-19 Python程式設計師

Python部落(python.freelycode.com)組織翻譯,禁止轉載,歡迎轉發。

我們在面試一份工作,面試官要求從代碼塊中刪除所有的for循環。然後他們提到一些關於迭代器的觀點同時手指敲打在桌子上並瘋狂地大笑。我們很緊張,並且對被分配這個可笑的任務感到沮喪,但是我們將盡最大的努力。

為了理解不用for循環如何循環,我們需要找出for是怎麼運作的。

我們要學習在Python中for循環如何工作。在這個過程中,我們需要了解可迭代對象,迭代器和迭代協議。

使用下標循環:一次失敗的嘗試

我們可能首先嘗試通過使用來自於C的傳統循環風格來刪除for循環:使用下標循環。


這對list有效,但在set上行不通:


這種方法只適用於序列,它是含有索引從0到比序列長度小一的數據類型。列表、字符串和元組是序列。字典、集合和許多其它的可迭代對象不是序列。

我們按照指示實現一個適用於所有可迭代對象而不只是序列的循環結構。

可迭代對象是什麼?

在Python的世界,一個可迭代對象你可以使用一個for循環來進行循環的任何對象

可迭代對象不總是可索引的,因為它們不總有長度,而且它們不總是有限的。

下面是一個無限的迭代對象,循環時它得到5的倍數:


當我們使用for循環時,我們可以循環遍歷這個迭代,像這樣:


如果我們從上面的for循環刪除break條件,它將永遠繼續列印。

因此可循環對象可以無限長:這意味著在我們遍歷一個可循環對象之前,我們不總是能把它轉換成一個列表(或者其它的序列)。我們需要以某種方式讓可迭代對象中的每一項分別迭代,同樣的方式for循環適用。

可迭代對象和迭代器

好吧,我們已經定義了可迭代對象,但是可迭代對象究竟如何在Python中運作?

可以傳遞所有的可迭代對象到內置的iter函數來得到一個迭代器。


這是一個有趣的事實,但是什麼是迭代器?

迭代器只有一個工作:返回可迭代對象中的「下一個」項。迭代器有點像tally counters,但是它們沒有一個復位按鈕,而且在可迭代對象中它們給出下一個項,而不是給出下一個數字。

從任何可迭代對象可以得到一個迭代器:


並且可以傳遞迭代器到next函數來得到它們的下一項:


因此可以傳遞迭代器到內置的next函數來得到下一項,並且如果沒有下一項(因為已經到達結尾)將引發一個StopIteration異常。

迭代器也是可迭代對象

因此在可迭代對象上調用iter得到迭代器。而且在迭代器上調用next得到下一項或者如果沒有更多項引發一個StopIteration異常。

實際上不止這些。可以傳遞迭代器到內置的iter函數來返回它們自身。這意味著迭代器也是可迭代對象。


這一事實導致了一些有趣的後果,而那我們目前沒有時間深入。我們將保存這個討論作為未來的學習探索……

迭代協議

迭代協議是一個很有意思的術語,它的意思是「可迭代對象在Python中究竟如何運作」。

讓我們從Python的角度重新定義可迭代對象。

可迭代對象:

    1. 可以被傳遞到iter函數來得到可迭代對象。

    2. 沒有第2個。需要一個可迭代對象。

迭代器:

    1. 可以被傳遞到next函數,而這得到它們的下一項或者引發StopIteration

    2. 當被傳遞到iter函數,返回它們自身。

這些話反過來也成立。意思是:

    1. 傳遞到iter沒有任何錯誤的任何東西是一個可迭代對象。

    2. 傳遞到next沒有任何錯誤(除了StopIteration)的任何東西是一個迭代器。

    3. 傳遞到iter返回返回自身的任何東西是一個迭代器。

使用迭代器循環

根據我們學到的關於可迭代對象和迭代器的知識,現在應該可以不使用for循環重建一個for循環。這個while循環手動循環某些iterable,列印每個項:


我們可以使用任何可迭代對象調用這個函數,並且它將循環:


上述函數基本上與使用一個for循環的函數相同:


這個for循環自動地做我們手動做的工作:調用iter來得到一個可迭代對象,然後重複調用next直到引發StopIteration異常。

迭代協議用於for循環、元組拆封和所有適用通用可迭代對象的內置函數。使用迭代協議(手動或自動)是唯一的在Python中任何可迭代對象循環的通用方法。

For循環:比它們看起來更複雜

現在我們準備完成面試官分配的非常愚蠢的任務。我們將通過手動使用iter和next循環可迭代對象,從代碼中刪除所有的for循環。在研究這個任務中,我們學到了什麼?

所有你可以循環的是一個可迭代對象。循環可迭代對象通過從一個可迭代對象得到迭代器,然後重複請求迭代器得到下一個項來工作。

迭代器和可迭代對象工作的方式稱為迭代協議。列表生成式、元組拆封、for循環和所有其它的迭代協議中迭代依賴的形式。

我會在以後的文章中更多的探討迭代器。目前知道迭代器是Python中所有迭代的幕後。

英文原文:http://treyhunner.com/2016/12/python-iterator-protocol-how-for-loops-work/
譯者:蒲公英

相關焦點

  • 更深入理解 Python 中的迭代
    (點擊上方公眾號,可快速關注)編譯: linux中國 / MjSeven   英文:  Trey Hunnerhttps://
  • 【Python基礎】可迭代對象&迭代器對象及其實現
    首選確保for循環的in後面是一個可迭代對象,這樣就能通過python內置函數iter()得到一個迭代器對象(iterator)迭代列表時候,我們看看了列表下__開頭的方法,其中的__iter__()就是迭代協議的接口。
  • python:控制流程 - for迭代循環
    #pythonfor迭代的要點for 後面需要接上可迭代對象for會依次取出可迭代對象中的元素5.continue的用法:continue和break類似,但是continue不會終止循環,而是結束本次循環
  • Python 2.x 與 Python 3.x 的區別
    Python 中的除法有兩個運算符,/ 和 // 首先來說下 / 除法:在 python 2.x 中 / 除法就跟我們熟悉的大多數語言,比如 Java、C 差不多,整數相除的結果是一個整數,把小數部分完全忽略掉,浮點數除法會保留小數點的部分得到一個浮點數的結果。在 python3.x 中 / 除法不再這麼做了,對於整數之間的相除,結果也會是浮點數。
  • 20招讓你的 Python 飛起來!
    絕對乾貨,童叟無欺,主要分享了提升 Python 性能的 20 個技巧,教你如何告別慢Python。原文作者 開元,全棧程式設計師,使用 Python, Java, PHP和C++。, best of 3: 3.69 ms per loop100 loops, best of 3: 5.61 ms per loopwhile 1 比 while true快很多,原因是在python2.x中,True是一個全局變量,而非關鍵字。
  • Python 性能優化的20條招數
    , best of 3: 3.69 ms per loop100 loops, best of 3: 5.61 ms per loopwhile 1 比 while true 快很多,原因是在 python2.x 中,True 是一個全局變量,而非關鍵字。
  • Python性能優化的20條招數
    快很多,原因是在 python2.x 中,True 是一個全局變量,而非關鍵字。ctypes: 通常用於封裝(wrap)C程序,讓純 Python 程序調用動態連結庫(Windows 中的 dll 或 Unix 中的 so 文件)中的函數。如果想要在 python 中使用已經有C類庫,使用 ctypes 是很好的選擇,有一些基準測試下,python2+ctypes 是性能***的方式。
  • 帶你學習 Python 中優雅的 for 循環
    來自:Linux迷連結:https://www.linuxmi.com/python-for-loops.htmlFor循環是必不可少的編程技能
  • Python · numba 的基本應用
    所以上述add_with_vec的參數yy其實是輸入數組y中的元素,而不是y本身。更詳細的說明可以參見官方文檔)* 可以看到當常數 c 是整數和是浮點數時、速度是不同的。個人猜測這是因為若常數 c 為整數,那麼實際運算時需要將它轉化為浮點數,從而導致速度變慢* 上述代碼中我們沒有顯式地定義函數的參數類型和返回類型,但我們可以預先定義。
  • Python入門教程(四):用Python實現SQL中的分組聚合
    對於我來說呢,如果面對大量數據時,我會去計算相關數據的概括統計值,包括均值,標準差,中位數等等,它們可以讓我們概括出數據中的「經典值」。在數據分析中,我們常用到的工具是SQL,這些函數在SQL中你可能已經用的比較熟悉了,今天呢我們就講一講這些函數在Python中的應用。
  • Python生成器next方法和send方法區別詳解
    1.和傳統的容器相比,生成器更節省內存. 2.延遲計算,在我們需要結果時就調用一下生成器的next()方法即可. 3.可迭代,你可以像遍歷list一樣,遍歷生成器 三.如何創建生成器?在python中有兩種方式創建生成器:生成淺談Python中的可迭代對象、迭代器、For循環工作機制、生成器1.iterable iterator區別 要了解兩者區別,先要了解一下迭代器協議: 迭代器協議是指:對象需要提供__next__()方法,它返回迭代中的元素,在沒有更多元素後,拋出StopIteration異常,終止迭代. 可迭代對象就是:實現了迭代器協議的對象.
  • Python性能分析技巧
    在本文中,我們將學習一些Ipython的命令,這些命令可以幫助我們對Python代碼進行時間分析。1.分析一行代碼要檢查一行python代碼的執行時間,請使用**%timeit**。下面是一個簡單的例子來了解它的工作原理:#### magics命令%timeit的簡單用法%timeit [num for num in range(20)]#### 輸出1.08 µs ± 43 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)它返回代碼運行的平均值和標準偏差
  • 如何快速學會Python處理數據?(5000字走心總結)
    1 如何學好Python 1.1 明確自己的需求(最好是剛需)聽到別人說Python很牛很厲害,也想跟著學,這樣的人肯定是學不好python的。沒有明確的需求和動力,就會導致你學python兩天打魚三天曬網,沒有恆心也沒有決心。
  • Python中的for循環
    # 循環允許我們重複執行一個代碼或代碼塊 # python中的循環 # for循環 # while循環 # for循環是一種迭代循環機制,而while循環是條件循環,迭代即重複相同的邏輯操作
  • 高性能Python:使用Cython
    本文分享自:http://blog.soliloquize.org/Cython安裝Cython可以通過pip直接進行安裝,pip install cythonCython代碼編譯與使用以一個簡短的代碼樣例來看下Cython如何使用,定義一個.pyx文件,
  • 一行代碼讓你的Python運行速度提高100倍!Python真強!
    今天,帶大家學習如何讓Python飛起來的方法,乾貨滿滿哦!python一直被病垢運行速度太慢,但是實際上python的執行效率並不慢,慢的是python用的解釋器Cpython運行效率太差。「一行代碼讓python的運行速度提高100倍」這絕不是譁眾取寵的論調。我們來看一下這個最簡單的例子,從1一直累加到1億。
  • 獨家 | 帶你入門比Python更高效的Numpy(附代碼)
    數據科學家介紹了向量化技巧,簡單的數學變化可以通過可迭代對象執行。簡介向量化技巧對於數據科學家來說是相當熟知的,並且常用於編程中,以加速整體數據轉換,其中簡單的數學變化通過可迭代對象(例如列表)執行。未受到重視的是,把有一定規模的代碼模塊,如條件循環,進行矢量化,也能帶來一些好處。
  • 解密Python中的args和kwargs
    有時候,當你查看Python中的函數時,可能會看到它有兩個奇怪的參數:*args和**kwargs。如果你曾經感到疑惑:這些特殊的變量是什麼,為什麼你的IDE在main()中定義它們,那麼本文就是為你量身定做的。你將學習如何在Python中使用這兩個參數來增加函數的靈活性。
  • 如何在Stata16中調用Python
    :可進入Python環境,但這種進入並不穩定,一旦出現錯誤就會回到Stata環境中。2 數據交互本節介紹如何在Stata的數據類型和Python的數據類型之間進行轉換。其適用情境為:數據已經在Stata內存(數據編輯器)中,但想要使用Python的方法;比如,我們已經加載auto.dta數據集,但希望使用Python的matplotlib庫繪製一個以length為橫軸、weight為縱軸、price為尺寸的散點圖,並保存為dpi為300的png格式。
  • Python編程技巧:如何用Map, Filter, Reduce代替For循環?
    map、filter 和 reduce 這三種技術可以提供描述迭代原因的函數替代方案,以便避免過多的 for 循環。我之前在 JavaScript 中寫過這些技術的入門文章,但是它們在 Python 中的實現略有不同。