Python?enumerate()計數器簡化循環(huán)
摘要:
當我們需要計數和迭代中的值時,Pythonenumerate()允許編寫 Pythonicfor循環(huán)。最大的優(yōu)點enumerate()是它返回一個帶有計數器和值的元組,因此您不必自己增加計數器。它還為您提供了更改計數器起始值的選項。
在 Python 中,for循環(huán)通常被寫成對可迭代對象的循環(huán)。這意味著您不需要計數變量來訪問迭代中的項目。但有時,您確實希望有一個在每次循環(huán)迭代中都會發(fā)生變化的變量。您可以使用 Python enumerate()來同時從可迭代對象中獲取計數器和值,而不是自己創(chuàng)建和增加變量!
在本教程中,我們將學到:
- 用于
enumerate()在循環(huán)中獲取計數器 - 適用
enumerate()于顯示項目計數 enumerate()與條件語句一起使用- 實現(xiàn)自己的同等功能,以
enumerate()
- 解包返回的值
enumerate()
讓我們開始吧!
一、for在 Python 中使用循環(huán)進行迭代
forPython 中的循環(huán)使用基于集合的迭代。這意味著 Python 在每次迭代時將迭代中的下一項分配給循環(huán)變量,如下例所示:
>>> >>> values = ["a", "b", "c"] >>> for value in values: ... print(value) ... a b c
在這個例子中,values是一個名單有三個字符串,"a","b",和"c"。在 Python 中,列表是一種可迭代對象。在for循環(huán)中,循環(huán)變量是value。在循環(huán)的每次迭代中,value設置為 的下一項values。
接下來,我們打印 value到屏幕上?;诩系牡膬?yōu)勢在于它有助于避免其他編程語言中常見的逐一錯誤。
現(xiàn)在想象一下,除了值本身之外,您還想在每次迭代時將列表中項目的索引打印到屏幕上。
處理此任務的一種方法是創(chuàng)建一個變量來存儲索引并在每次迭代時更新它:
>>> >>> index = 0 >>> for value in values: ... print(index, value) ... index += 1 ... 0 a 1 b 2 c
在本例中,index是一個整數,用于跟蹤您在列表中的距離。在循環(huán)的每次迭代中,您打印index以及value. 循環(huán)的最后一步是將存儲的數字更新index一。
當您忘記index在每次迭代時更新時,會出現(xiàn)一個常見錯誤:
>>> >>> index = 0 >>> for value in values: ... print(index, value) ... 0 a 0 b 0 c
在這個例子中,index在0每次迭代時都保持 at ,因為沒有代碼在循環(huán)結束時更新它的值。特別是對于長或復雜的循環(huán),這種錯誤是出了名的難以追蹤。
解決此問題的另一種常見方法是使用range()結合len()自動創(chuàng)建索引。這樣,您就不需要記住更新索引:
>>> >>> for index in range(len(values)): ... value = values[index] ... print(index, value) ... 0 a 1 b 2 c
在本例中,len(values)返回 的長度values,即3。然后range()創(chuàng)建一個迭代器,從默認的起始值開始運行,0直到它達到len(values)負一。在這種情況下,index成為您的循環(huán)變量。在循環(huán)中,您將當前值設置為value等于 中的項目。最后,您打印和。valuesindexindexvalue
在此示例中,可能發(fā)生的一個常見錯誤是您value在每次迭代開始時忘記更新。這類似于之前忘記更新索引的錯誤。這是該循環(huán)不被視為Pythonic 的原因之一。
這個例子也有一些限制,因為values必須允許使用整數索引訪問它的項目。允許這種訪問的可迭代對象在 Python中稱為序列。
技術細節(jié):根據Python 文檔,可迭代對象是可以一次返回一個成員的任何對象。根據定義,可迭代對象支持迭代器協(xié)議,該協(xié)議指定在迭代器中使用對象時如何返回對象成員。
Python 有兩種常用的可迭代類型:
- 序列
- 發(fā)電機
任何可迭代對象都可以在for循環(huán)中使用,但只能通過整數索引訪問序列。
嘗試通過生成器或迭代器的索引訪問項目將引發(fā)TypeError:
>>> >>> enum = enumerate(values) >>> enum[0] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'enumerate' object is not subscriptable
在此示例中,您將返回值分配enumerate()給enum。enumerate()是一個迭代器,因此嘗試通過索引訪問其值會引發(fā)TypeError.
幸運的是,Pythonenumerate()可以讓您避免所有這些問題。它是一個內置函數,這意味著自從2003 年在 Python 2.3中添加它以來,它在每個版本的 Python 中都可用。
二、使用 Python 的 enumerate()
您可以enumerate()以與使用原始可迭代對象幾乎相同的方式在循環(huán)中使用。不是將可迭代對象直接in放在for循環(huán)之后,而是將它放在enumerate().
我們還必須稍微更改循環(huán)變量,如下例所示:
>>> >>> for count, value in enumerate(values): ... print(count, value) ... 0 a 1 b 2 c
當我們使用 時enumerate(),該函數會返回兩個循環(huán)變量:
- 該計數當前迭代的
- 當前迭代中項目的值
就像普通for循環(huán)一樣,循環(huán)變量可以任意命名。您在本例中使用count和value,但它們可以命名為i和/v或任何其他有效的 Python 名稱。
使用enumerate() ,您不需要記住從可迭代對象訪問該項目,并且您不需要記住在循環(huán)結束時推進索引。一切都由 Python 的魔力自動為您處理!
技術細節(jié):使用兩個循環(huán)變量count和value,用逗號分隔是參數解包的一個例子。本文稍后將進一步討論這個強大的 Python 特性。
Pythonenumerate()有一個額外的參數,您可以使用它來控制計數的起始值。默認情況下,起始值是0因為 Python 序列類型從零開始索引。換句話說,當您想要檢索列表的第一個元素時,您可以使用 index 0:
>>> >>> print(values[0]) a
我們可以在此示例中看到,使用values索引訪問0會給出第一個元素a。但是,很多時候您可能不希望從enumerate()開始計數0。例如,您可能希望打印一個自然計數數作為用戶的輸出。在這種情況下,您可以使用start參數 forenumerate()來更改起始計數:
>>> >>> for count, value in enumerate(values, start=1): ... print(count, value) ... 1 a 2 b 3 c
在本例中,您傳遞start=1,它從第一次循環(huán)迭代count的值開始1。將此與前面的示例進行比較,其中start的默認值為0,看看您是否能發(fā)現(xiàn)差異。
三、用 Python 練習 enumerate()
我們應該enumerate()在需要在循環(huán)中使用計數和項目的任何時候使用。請記住,enumerate()每次迭代都會將計數加一。但是,這只是略微限制了您的靈活性。由于計數是標準的 Python 整數,因此您可以通過多種方式使用它。在接下來的幾節(jié)中,您將看到enumerate().
1.可迭代項的自然計數
在上一節(jié)中,您看到了如何使用enumerate()withstart創(chuàng)建一個自然計數數字來為用戶打印。enumerate()在 Python 代碼庫中也像這樣使用。您可以在腳本中看到一個示例,它讀取 reST 文件并在出現(xiàn)格式問題時告訴用戶。
注意: reST,也稱為reStructured Text,是 Python 用于文檔的文本文件的標準格式。您經常會看到在 Python 類和函數中包含作為文檔字符串的 reST 格式的字符串。讀取源代碼文件并告訴用戶格式問題的腳本稱為linter,因為它們在代碼中尋找隱喻的lint。
這個例子是從rstlint. 不要太擔心這個函數如何檢查問題。關鍵是要展示在現(xiàn)實世界中的使用enumerate():
1def check_whitespace(lines):
2 """Check for whitespace and line length issues."""
3 for lno, line in enumerate(lines):
4 if "\r" in line:
5 yield lno+1, "\\r in line"
6 if "\t" in line:
7 yield lno+1, "OMG TABS!!!1"
8 if line[:-1].rstrip(" \t") != line[:-1]:
9 yield lno+1, "trailing whitespace"
check_whitespace()接受一個參數,lines,它是應該評估的文件行。在 的第三行check_whitespace() ,enumerate()用于循環(huán) over lines。這將返回行號,縮寫為lno和line。由于start未使用,因此lno是文件中行的從零開始的計數器。check_whitespace()然后對不合適的字符進行多次檢查:
- 回車 ( \r)
- 制表符 ( \t)
- 行尾的任何空格或制表符
當這些項目之一存在時,為用戶check_whitespace() 產生當前行號和有用的消息。計數變量lno已1添加到其中,以便它返回計數行號而不是從零開始的索引。當 的用戶rstlint.py閱讀消息時,他們將知道要轉到哪一行以及要修復的內容。
2.跳過項目的條件語句
使用條件語句來處理項目是一種非常強大的技術。有時您可能只需要在循環(huán)的第一次迭代上執(zhí)行操作,如下例所示:
>>>
>>> users = ["Test User", "Real User 1", "Real User 2"]
>>> for index, user in enumerate(users):
... if index == 0:
... print("Extra verbose output for:", user)
... print(user)
...
Extra verbose output for: Test User
Real User 1
Real User 2
在此示例中,您將列表用作用戶的模擬數據庫。第一個用戶是您的測試用戶,因此您希望打印有關該用戶的額外診斷信息。由于您已將系統(tǒng)設置為首先測試用戶,因此您可以使用循環(huán)的第一個索引值來打印額外的詳細輸出。
我們還可以將數學運算與計數或索引的條件結合起來。例如,您可能需要從可迭代對象中返回項目,但前提是它們具有偶數索引。您可以使用enumerate()以下方法執(zhí)行此操作:
>>> >>> def even_items(iterable): ... """Return items from ``iterable`` when their index is even.""" ... values = [] ... for index, value in enumerate(iterable, start=1): ... if not index % 2: ... values.append(value) ... return values ...
even_items()接受一個名為 的參數,iterable它應該是 Python 可以循環(huán)遍歷的某種類型的對象。首先,values被初始化為一個空列表。然后你用和 set創(chuàng)建一個for循環(huán)。iterableenumerate()start=1
內for循環(huán),你檢查除以余下是否index通過2為零。如果是,則將該項目附加到values. 最后,您返回 values。
您可以使用列表推導式在一行中執(zhí)行相同的操作,而無需初始化空列表,從而使代碼更加Pythonic:
>>> >>> def even_items(iterable): ... return [v for i, v in enumerate(iterable, start=1) if not i % 2] ...
在此示例代碼中,even_items()使用列表推導式而不是for循環(huán)從列表中提取索引為偶數的每個項目。
您可以even_items()通過從1到的整數范圍中獲取偶數索引項來驗證它是否按預期工作10。結果將是[2, 4, 6, 8, 10]:
>>> >>> seq = list(range(1, 11)) >>> print(seq) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> even_items(seq) [2, 4, 6, 8, 10]
正如預期的那樣,從even_items()返回偶數索引項seq。當您使用整數時,這不是獲得偶數的最有效方法。但是,現(xiàn)在您已經驗證它even_items()可以正常工作,您可以獲得 ASCII 字母表的偶數索引字母:
>>> >>> alphabet = "abcdefghijklmnopqrstuvwxyz" >>> even_items(alphabet) ['b', 'd', 'f', 'h', 'j', 'l', 'n', 'p', 'r', 't', 'v', 'x', 'z']
alphabet是一個字符串,它包含 ASCII 字母表的所有 26 個小寫字母。調用even_items()和傳遞alphabet返回字母表中交替字母的列表。
Python 字符串是序列,可用于循環(huán)以及整數索引和切片。因此,對于字符串,您可以使用方括號even_items()更有效地實現(xiàn)相同的功能:
>>> >>> list(alphabet[1::2]) ['b', 'd', 'f', 'h', 'j', 'l', 'n', 'p', 'r', 't', 'v', 'x', 'z']
在這里使用字符串切片,你給出起始索引1,它對應于第二個元素。第一個冒號之后沒有結束索引,因此 Python 會轉到字符串的末尾。然后添加第二個冒號,后跟 a,2以便 Python 將采用所有其他元素。
但是,正如您之前看到的,生成器和迭代器不能被索引或切片,因此您仍然會發(fā)現(xiàn)它們enumerate()很有用。要繼續(xù)上一個示例,您可以創(chuàng)建一個生成器函數,根據需要生成字母表中的字母:
>>> >>> def alphabet(): ... alpha = "abcdefghijklmnopqrstuvwxyz" ... for a in alpha: ... yield a >>> alphabet[1::2] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'function' object is not subscriptable >>> even_items(alphabet()) ['b', 'd', 'f', 'h', 'j', 'l', 'n', 'p', 'r', 't', 'v', 'x', 'z']
在此示例中,您定義alphabet()了一個生成器函數,當該函數在循環(huán)中使用時,它會一個一個地生成字母表中的字母。Python 函數,無論是生成器還是常規(guī)函數,都無法通過方括號索引訪問。你在第二行試試這個,它會引發(fā)一個TypeError.
不過,您可以在循環(huán)中使用生成器函數,并且您可以在最后一行傳遞alphabet()給even_items(). 可以看到結果和前面兩個例子是一樣的。
四、理解 Python enumerate()
在最后幾節(jié)中,您看到了何時以及如何enumerate()發(fā)揮優(yōu)勢的示例?,F(xiàn)在您已經掌握了 的實際方面enumerate(),您可以了解更多有關該函數如何在內部工作的信息。
為了更好地了解enumerate()工作原理,您可以使用 Python 實現(xiàn)您自己的版本。您的版本enumerate()有兩個要求。這應該:
- 接受一個可迭代和一個起始計數值作為參數
- 發(fā)回一個包含當前計數值和可迭代對象相關項的元組
Python 文檔中給出了一種編寫滿足這些規(guī)范的函數的方法:
>>> >>> def my_enumerate(sequence, start=0): ... n = start ... for elem in sequence: ... yield n, elem ... n += 1 ...
my_enumerate()接受兩個參數,sequence和start。默認值start是0。在函數定義中,您初始化n為 的值start并for在sequence.
對于每一個elem在sequence你yield控制返回給調用位置和發(fā)送回的當前值n和elem。最后,您遞增n以準備下一次迭代。您可以my_enumerate()在此處查看實際操作:
>>> >>> seasons = ["Spring", "Summer", "Fall", "Winter"] >>> my_enumerate(seasons) <generator object my_enumerate at 0x7f48d7a9ca50> >>> list(my_enumerate(seasons)) [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] >>> list(my_enumerate(seasons, start=1)) [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
首先,您創(chuàng)建要使用的四個季節(jié)的列表。接下來,您將展示調用my_enumerate()with seasonsassequence創(chuàng)建一個生成器對象。這是因為您使用yield關鍵字將值發(fā)送回調用者。
最后,創(chuàng)建兩個列表my_enumerate() ,在其中起始值被保留為默認,0在其中,一個start改變?yōu)?。在這兩種情況下,您最終都會得到一個元組列表,其中每個元組的第一個元素是計數,第二個元素是來自 的值seasons。
盡管您enumerate()只需幾行 Python 代碼即可實現(xiàn)等效的函數,但實際的代碼enumerate() 是用 C 編寫的。這意味著它超級快速和高效。
五、解包參數 enumerate()
當您enumerate()在for循環(huán)中使用時,您告訴 Python 使用兩個變量,一個用于計數,另一個用于值本身。您可以通過使用稱為參數解包的 Python 概念來做到這一點。
參數解包的思想是,一個元組可以根據序列的長度分成幾個變量。例如,您可以將包含兩個元素的元組解包為兩個變量:
>>> >>> tuple_2 = (10, "a") >>> first_elem, second_elem = tuple_2 >>> first_elem 10 >>> second_elem 'a'
首先,您創(chuàng)建一個包含兩個元素的元組,10和"a"。然后將該元組解包到first_elemand 中second_elem,每個都從元組中分配一個值。
當您調用enumerate()并傳遞一系列值時,Python 會返回一個迭代器。當您向迭代器詢問其下一個值時,它會生成一個包含兩個元素的元組。元組的第一個元素是計數,第二個元素是您傳遞的序列中的值:
>>> >>> values = ["a", "b"] >>> enum_instance = enumerate(values) >>> enum_instance <enumerate at 0x7fe75d728180> >>> next(enum_instance) (0, 'a') >>> next(enum_instance) (1, 'b') >>> next(enum_instance) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
在此示例中,您創(chuàng)建了一個列表,該列表values包含兩個元素"a"和"b"。然后傳遞values給enumerate()并將返回值分配給enum_instance . 當您打印時enum_instance ,您可以看到它是一個enumerate()具有特定內存地址的實例。
然后使用 Python 的內置next()函數從enum_instance. enum_instance返回的第一個值是一個元組,其中包含計數0和來自 的第一個元素values,即"a"。
next()再次調用on 會enum_instance產生另一個元組,這次是計數1和來自values,的第二個元素"b"。最后,由于沒有更多的值要從 返回,所以再調用next()一次會增加。StopIterationenum_instance
在for循環(huán)中使用可迭代對象時,Python 會next()在每次迭代開始時自動調用,直到StopIteration引發(fā)。Python 將從可迭代對象中檢索到的值分配給循環(huán)變量。
如果可迭代對象返回一個元組,則可以使用參數解包將元組的元素分配給多個變量。這是您在本教程前面通過使用兩個循環(huán)變量所做的。
另一次您可能已經看到使用for循環(huán)解包參數是使用內置的zip(),它允許您同時迭代兩個或多個序列。
在每次迭代中,zip()返回一個元組,該元組從所有傳遞的序列中收集元素:
>>> >>> first = ["a", "b", "c"] >>> second = ["d", "e", "f"] >>> third = ["g", "h", "i"] >>> for one, two, three in zip(first, second, third): ... print(one, two, three) ... a d g b e h c f i
通過使用zip(),可以遍歷first,second以及third在同一時間。在for循環(huán)中,您分配元素 from firstto one、 from secondtotwo和 from thirdto three。然后打印三個值。
我們可以組合zip()和enumerate()使用嵌套參數解包:
>>> >>> for count, (one, two, three) in enumerate(zip(first, second, third)): ... print(count, one, two, three) ... 0 a d g 1 b e h 2 c f i
在for此示例的循環(huán)中,您嵌套zip()在enumerate(). 這意味著每次for循環(huán)迭代時,都會enumerate()產生一個元組,其中第一個值作為計數,第二個值作為另一個元組,其中包含從參數到 的元素zip()。要解壓嵌套結構,您需要添加括號以從zip().
還有其他方法可以模擬enumerate()與zip(). 一種方法使用itertools.count(),它默認返回從零開始的連續(xù)整數。您可以將前面的示例更改為使用itertools.count():
>>> >>> import itertools >>> for count, one, two, three in zip(itertools.count(), first, second, third): ... print(count, one, two, three) ... 0 a d g 1 b e h 2 c f i
用itertools.count()在這個例子中,您可以使用一個單一的zip()呼叫產生計數以及沒有嵌套參數拆包的循環(huán)變量。
六、結論
當您需要計數和迭代中的值時,Pythonenumerate()允許您編寫 Pythonicfor循環(huán)。最大的優(yōu)點enumerate()是它返回一個帶有計數器和值的元組,因此您不必自己增加計數器。它還為您提供了更改計數器起始值的選項。
總結:
enumerate()在for循環(huán)中使用Python- 應用
enumerate()在幾個現(xiàn)實世界的例子中 enumerate()使用參數解包獲取值- 實現(xiàn)自己的同等功能,以
enumerate()
我們還看到enumerate()在一些實際代碼中使用,包括在CPython代碼存儲庫中。您現(xiàn)在擁有簡化循環(huán)并使 Python 代碼時尚的超能力!
到此這篇關于Python enumerate()計數器簡化循環(huán)的文章就介紹到這了,更多相關Python enumerate內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python 統(tǒng)計list中各個元素出現(xiàn)的次數的幾種方法
這篇文章主要介紹了python 統(tǒng)計list中各個元素出現(xiàn)的次數的幾種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-02-02
win10下opencv-python特定版本手動安裝與pip自動安裝教程
這篇文章主要介紹了win10下opencv-python特定版本手動安裝與pip自動安裝教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03
Python實戰(zhàn)之實現(xiàn)簡單的名片管理系統(tǒng)
這篇文章主要介紹了Python實戰(zhàn)之實現(xiàn)簡單的名片管理系統(tǒng),文中有非常詳細的代碼示例,對正在學習python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04

