將 Python 物件轉換為迭代器
Python 中的迭代器是我們將迴圈遍歷的那些項,或者換句話說,迭代。我們可以將任何物件更改為迭代器,甚至可以在 __iter__()
和 __next__()
方法的幫助下建立我們的迭代器。
當我們必須以迭代器的形式訪問某些物件時,它很有用。我們可以使用生成器迴圈來做到這一點,但是這些很耗時並且會使程式碼變得龐大。
Python 的內建方法 __iter__()
更適合此類任務。
在 Python 中使用 __iter__()
和 __next__()
方法將物件轉換為迭代器
顧名思義,迭代器會一一返回資料值。迭代器物件在 __iter__()
和 __next__()
方法的幫助下執行此操作。
__iter__()
和 __next__()
方法一起構成了迭代器協議。讓我們討論一些例子來理解迭代器協議的基本工作。
demo = ("volvo", "ferrari", "audi")
val = iter(demo)
print(next(val))
print(next(val))
print(next(val))
輸出:
volvo
ferrari
audi
在這裡,我們有一個包含三個值的元組。我們使用 __iter__()
方法從這個元組物件中一一獲取值。
此外,__next__()
方法一個接一個地遍歷這些值。我們可以不同地使用 __next__()
方法,就像這樣。
demo = ("volvo", "ferrari", "audi")
val = iter(demo)
print(val.__next__())
print(val.__next__())
print(val.__next__())
輸出:
volvo
ferrari
audi
現在我們也得到了相同的輸出。PEP 3114 將 iterator.next()
更改為 iterator.__next__()
。我們可以將這些方法與任何可迭代物件一起使用。
這是一個使用字串的示例。
demostr = "volvo"
val = iter(demostr)
print(next(val))
print(next(val))
print(next(val))
print(next(val))
print(next(val))
輸出:
v
o
l
v
o
Python 有許多可迭代的內建容器——字串、列表、元組。我們可以使用 __iter__()
函式從可迭代物件中建立物件。
此外,我們可以使用 __next__()
方法逐個訪問物件。
語法:
iter(object_name)
iter(callable, sentinel)
在這裡,object_name
指的是物件,如列表或元組,其迭代器將被建立。此外,callable
是指可呼叫物件,sentinel
是指給出迭代終止條件的值。
sentinel 值顯示了我們正在迭代的序列的結尾。因此,如果我們在所有物件都已經被迭代時呼叫迭代器,我們會得到 StopIterationError
異常。
請注意,建立迭代器不會更改可迭代物件。看看這個演示 StopIterationError
的示例。
li = ["volvo", "ferrari", "audi"]
value = li.__iter__()
print(value.__next__())
print(value.__next__())
print(value.__next__())
print(value.__next__()) # Error occurs here
輸出:
volvo
ferrari
audi
StopIteration
我們甚至可以建立我們的物件或類作為迭代器。讓我們建立一個迭代器,它將返回一個數字序列,從 10 開始,其中每個值將增加 2。
class GetNumbers:
def __iter__(self):
self.x = 10
return self
def __next__(self):
a = self.x
self.x += 2
return a
myclass = GetNumbers()
value = iter(myclass)
print(next(value))
print(next(value))
print(next(value))
print(next(value))
print(next(value))
輸出:
10
12
14
16
18
在這裡,__iter__()
方法的工作方式類似於 __init__()
方法。我們可以在 __iter__()
方法中進行初始化或操作,但我們總是返回物件。
我們可以在 __next__()
方法的幫助下執行操作。但在這種情況下,返回值應該是序列的下一個元素。
在這裡,我們將 2 新增到 __next__()
方法中的每個值。
Python 中迭代器的屬性
為了理解內部工作,我們應該知道迭代器的一些屬性。這些如下:
- 迭代物件使用內部計數變數來保持迭代計數。
- 一旦迭代完成,我們不能再次將此迭代計數變數重新分配為 0。因此,出現
StopIteration
錯誤。 - 因此,我們可以說迭代計數變數只能遍歷一個容器一次。
這裡是文件連結,談到了 Python 中的迭代器。
現在讓我們看看迭代永遠不會結束的情況。這裡值得注意的一點是我們使用了 __next__()
方法一定次數。
但是如果迭代器物件永遠不會耗盡呢?在這種情況下,不可能多次編寫 __next__()
語句。
我們使用帶有兩個引數的 iter()
方法。第一個引數是可呼叫的,第二個引數是哨兵。
因此,當返回值與哨兵匹配時,迭代器停止。將以下程式碼貼上到你的編輯器中並嘗試執行它。
int()
value = iter(int, 1)
next(value)
輸出:
>>> 1
1
>>> 1
1
>>> 2
2
>>> 3
3
>>>
當你執行這段程式碼時,你會看到迭代器永遠不會停止。這是因為 int()
函式每次都返回 0
。
不管你給什麼值作為輸入,返回的值都不會與 sentinel 相同,這裡是 1。嘗試將 sentinel 的值更改為 0。
int()
value = iter(int, 0)
next(value)
輸出:
StopIteration
這一次,我們在第一次執行時得到了 StopIteration
異常。
我們建立迭代器的方式,我們也可以建立無限迭代器。讓我們建立一個無限迭代器,它將返回所有偶數的列表。
class Even:
def __iter__(self):
self.x = 0
return self
def __next__(self):
x = self.x
self.x += 2
return x
輸出:
>>> obj = iter(Even())
>>> next(obj)
0
>>> next(obj)
2
>>> next(obj)
4
>>>
使用迭代器的最大優點是它們可以幫助我們節省資源。請注意,如果我們使用變數,將會浪費大量空間。
但是在迭代器的幫助下,我們可以得到所有偶數,而不用擔心將它們儲存在記憶體中。
要了解有關 Python 中迭代器物件的更多資訊,請參閱此文件。
まとめ
在本文中,我們討論了 Python 中迭代器的概念。我們討論了 __iter__()
和 __next__()
方法的工作原理以及一些示例。
當我們想要使用無限值時,我們還看到了迭代器的使用如何提高記憶體效率。我們還使用迭代器協議製作了迭代器。