Python中的迭代器詳解
迭代器
迭代(iterate)意味著重復多次,就像循環(huán)那樣。工作中我們一定使用for循環(huán)迭代過列表和字典,但實際上也可迭代其他對象:實現(xiàn)了方法__iter__
的對象。方法__iter__
返回一個迭代器,它是包含方法__next__
的對象,而調(diào)用這個方法時可不提供任何參數(shù)。當你調(diào)用方法__next__
時,迭代器應返回其下一個值。如果迭代器沒有可供返回的值,應引發(fā)StopIteration異常。你還可使用內(nèi)置的便利函數(shù)next。
__iter__
用于定義一個可迭代對象(iterable)。通過實現(xiàn) __iter__
方法,我們可以使自定義的對象能夠被 for
循環(huán)等迭代器相關的操作使用。
python中哪些是可迭代對象呢?我們可以測試一下
def is_iterable(param): ? ?try: ? ? ? ?iter(param) ? ? ? ?return True ? ?except TypeError: ? ? ? ?return False ? ? params = [ ? ?1234, ? ?'1234', ? [1, 2, 3, 4], ? ?set([1, 2, 3, 4]), ? {1: 1, 2: 2, 3: 3, 4: 4}, ? (1, 2, 3, 4) ] ? for param in params: ? ?print(f'{param} is iterable? {is_iterable(param)}') ''' 1234 is iterable? False 1234 is iterable? True [1, 2, 3, 4] is iterable? True {1, 2, 3, 4} is iterable? True {1: 1, 2: 2, 3: 3, 4: 4} is iterable? True (1, 2, 3, 4) is iterable? True '''
可以看到列表、元組、字典、集合、字符串都是可迭代對象,查看源碼,發(fā)現(xiàn)他們都實現(xiàn)了__iter__
方法
def __iter__(self, *args, **kwargs): # real signature unknown ? ?""" Implement iter(self). """ ? ?pass ?
方法__iter__
返回一個迭代器,它是包含方法__next__
的對象,而調(diào)用這個方法時可不提供任何參數(shù)。當你調(diào)用方法__next__
時,迭代器應返回其下一個值。
實踐
示例一
迭代器實現(xiàn)斐波那契數(shù)列
class Fibs: ? ?def __init__(self): ? ? ? ?self.a = 0 ? ? ? ?self.b = 1 ? ? ?def __iter__(self): ? ? ? ?return FibIterator(self.a, self.b) ? ? class FibIterator: ? ? ?def __init__(self, a, b): ? ? ? ?self.a = a ? ? ? ?self.b = b ? ? ?def __next__(self): ? ? ? ?self.a, self.b = self.b, self.a + self.b ? ? ? ?return self.a ? ? ?def __iter__(self): ? ? ? ?return self ? ? fibs = Fibs() for f in fibs: ? ?print(f) ? ?if f > 10: ? ? ? ?break ''' 1 1 2 3 5 8 13 '''
這段代碼,Fibs
類是一個可迭代對象,并且在 __iter__
方法中返回一個迭代器對象 FibIterator(self.a, self.b)
。
FibIterator
類是一個迭代器對象,它包含 __next__
和 __iter__
方法。
在 FibIterator
的 __init__
方法中,初始化了兩個變量 self.a
和 self.b
分別表示斐波那契數(shù)列中的前兩個元素。
__next__
方法會根據(jù)迭代邏輯計算出下一個斐波那契數(shù),并將 self.a
和 self.b
更新為下一次迭代所需的值。然后,它返回當前的斐波那契數(shù)。
__iter__
方法在這個示例中實現(xiàn)了迭代器對象的自引用,即返回自身,使得迭代器對象本身也可以被迭代。
當你使用 for
循環(huán)迭代 fibs
對象時,它會調(diào)用 fibs
對象的 __iter__
方法獲取迭代器對象,然后重復調(diào)用迭代器對象的 __next__
方法來獲取斐波那契數(shù)列中的下一個數(shù)。
示例二
使用自定義的迭代器類來生成一個遞增序列
class IncrementIterator: ? ?def __init__(self, start, step): ? ? ? ?self.current = start ? ? ? ?self.step = step ? ? ?def __iter__(self): ? ? ? ?return self ? ? ?def __next__(self): ? ? ? ?value = self.current ? ? ? ?self.current += self.step ? ? ? ?return value ?
在這個例子中,IncrementIterator
類表示一個遞增序列的迭代器。它接受兩個參數(shù) start
和 step
,分別表示初始值和遞增步長。
__init__
方法初始化了兩個實例變量 self.current
和 self.step
,分別用于存儲當前值和遞增步長。
__iter__
方法返回迭代器對象本身,即 self
。這樣可以使迭代器對象本身也是可迭代的。
__next__
方法計算并返回當前值,并將 self.current
增加 self.step
,以準備下一次迭代。
以下是如何使用 IncrementIterator
迭代器生成遞增序列的示例代碼:
iterator = IncrementIterator(0, 2) for num in iterator: ? ?print(num) ? ?if num >= 10: ? ? ? ?break
這段代碼會生成一個從 0 開始,每次遞增 2 的遞增序列。在 for
循環(huán)中,迭代器對象 iterator
會自動調(diào)用 __iter__
方法獲取迭代器本身,并重復調(diào)用 __next__
方法來獲取下一個遞增值。
迭代器創(chuàng)建序列
對迭代器和可迭代對象進行迭代之外,還可將它們轉換為序列。比如下面這個例子
class TestIterator: ? ?value = 0 ? ? ?def __next__(self): ? ? ? ?self.value += 1 ? ? ? ?if self.value > 10: raise StopIteration ? ? ? ?return self.value ? ? ?def __iter__(self): ? ? ? ?return self ? ti = TestIterator() print(list(ti)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
這段代碼使用list顯式地將迭代器轉換為列表。
iter函數(shù)
可迭代對象調(diào)用 iter() 函數(shù),可以得到一個迭代器。迭代器可以通過 next() 函數(shù)來得到下一個元素,從而支持遍歷。
l = [1,2,3,4] it = iter(l) print(next(it)) # 1 print(type(it)) # <class 'list_iterator'>
使用迭代器的意義
有人說為啥要用迭代器,我用列表也可以呀,為啥不用列表呢?因為在很多情況下,你可能只想逐個地獲取值,而不是使用列表一次性獲取。這是因為如果有很多值,列表可能占用太多的內(nèi)存。使用迭代器相對于直接使用列表的優(yōu)勢在于節(jié)省內(nèi)存和提高性能。下面是一個例子來說明這一點:
我們需要生成一個非常大的數(shù)列,比如一個包含 1 到 1000000 的連續(xù)整數(shù)序列。如果我們使用列表來存儲這個數(shù)列,就需要將所有的數(shù)都存儲在內(nèi)存中,這會消耗大量的內(nèi)存空間。
my_list = list(range(1, 1000001))
然而,如果我們使用迭代器來生成這個數(shù)列,只需要在需要使用時逐個生成數(shù)字,而不需要一次性存儲全部數(shù)字。這節(jié)省了大量的內(nèi)存空間。
class MyIterator: ? ?def __init__(self, start, end): ? ? ? ?self.current = start ? ? ? ?self.end = end ? ? ?def __iter__(self): ? ? ? ?return self ? ? ?def __next__(self): ? ? ? ?if self.current > self.end: ? ? ? ? ? ?raise StopIteration ? ? ? ?else: ? ? ? ? ? ?value = self.current ? ? ? ? ? ?self.current += 1 ? ? ? ? ? ?return value ? my_iterator = MyIterator(1, 1000000) ? for num in my_iterator: ? ?print(num)
過使用迭代器,我們避免了一次性將所有數(shù)字存儲在內(nèi)存中的需求,減少了內(nèi)存的占用。相比之下,使用列表則需要先生成并存儲所有數(shù)字,會占用大量的內(nèi)存。
此外,迭代器還具有惰性求值的特點,即只在需要時才生成下一個元素。這種特性在處理大量數(shù)據(jù)時非常有用,可以減少不必要的計算和處理時間。
因此,使用迭代器可以節(jié)省內(nèi)存,并在處理大量數(shù)據(jù)時提高性能。它們可以逐個生成序列中的元素,而無需一次性將所有元素存儲在內(nèi)存中。
最后
通過上述例子,可以知道實現(xiàn)了方法__iter__
的對象是可迭代的,而實現(xiàn)了方法__next__
的對象是迭代器。
以上就是Python中的迭代器詳解的詳細內(nèi)容,更多關于Python迭代器的資料請關注腳本之家其它相關文章!
相關文章
ndarray的轉置(numpy.transpose()與A.T命令對比分析)
這篇文章主要介紹了ndarray的轉置(numpy.transpose()與A.T命令對比分析),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02Python Flask全棧項目實戰(zhàn)構建在線書店流程
這篇文章主要為大家介紹了Python Flask全流程全棧項目實戰(zhàn)之在線書店構建實現(xiàn)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11Python線性網(wǎng)絡實現(xiàn)分類糖尿病病例
什么是線性規(guī)劃?想象一下,您有一個線性方程組和不等式系統(tǒng)。這樣的系統(tǒng)通常有許多可能的解決方案。線性規(guī)劃是一組數(shù)學和計算工具,可讓您找到該系統(tǒng)的特定解,該解對應于某些其他線性函數(shù)的最大值或最小值2022-10-10