Python中的迭代器详解
作者:郝同学的测开笔记
迭代器
迭代(iterate)意味着重复多次,就像循环那样。工作中我们一定使用for循环迭代过列表和字典,但实际上也可迭代其他对象:实现了方法__iter__
的对象。方法__iter__
返回一个迭代器,它是包含方法__next__
的对象,而调用这个方法时可不提供任何参数。当你调用方法__next__
时,迭代器应返回其下一个值。如果迭代器没有可供返回的值,应引发StopIteration异常。你还可使用内置的便利函数next。
__iter__
用于定义一个可迭代对象(iterable)。通过实现 __iter__
方法,我们可以使自定义的对象能够被 for
循环等迭代器相关的操作使用。
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 '''
可以看到列表、元组、字典、集合、字符串都是可迭代对象,查看源码,发现他们都实现了__iter__
方法
def __iter__(self, *args, **kwargs): # real signature unknown """ Implement iter(self). """ pass
方法__iter__
返回一个迭代器,它是包含方法__next__
的对象,而调用这个方法时可不提供任何参数。当你调用方法__next__
时,迭代器应返回其下一个值。
实践
示例一
迭代器实现斐波那契数列
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
分别表示斐波那契数列中的前两个元素。
__next__
方法会根据迭代逻辑计算出下一个斐波那契数,并将 self.a
和 self.b
更新为下一次迭代所需的值。然后,它返回当前的斐波那契数。
__iter__
方法在这个示例中实现了迭代器对象的自引用,即返回自身,使得迭代器对象本身也可以被迭代。
当你使用 for
循环迭代 fibs
对象时,它会调用 fibs
对象的 __iter__
方法获取迭代器对象,然后重复调用迭代器对象的 __next__
方法来获取斐波那契数列中的下一个数。
示例二
使用自定义的迭代器类来生成一个递增序列
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
类表示一个递增序列的迭代器。它接受两个参数 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
循环中,迭代器对象 iterator
会自动调用 __iter__
方法获取迭代器本身,并重复调用 __next__
方法来获取下一个递增值。
迭代器创建序列
对迭代器和可迭代对象进行迭代之外,还可将它们转换为序列。比如下面这个例子
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函数
可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素,从而支持遍历。
l = [1,2,3,4] it = iter(l) print(next(it)) # 1 print(type(it)) # <class 'list_iterator'>
使用迭代器的意义
有人说为啥要用迭代器,我用列表也可以呀,为啥不用列表呢?因为在很多情况下,你可能只想逐个地获取值,而不是使用列表一次性获取。这是因为如果有很多值,列表可能占用太多的内存。使用迭代器相对于直接使用列表的优势在于节省内存和提高性能。下面是一个例子来说明这一点:
我们需要生成一个非常大的数列,比如一个包含 1 到 1000000 的连续整数序列。如果我们使用列表来存储这个数列,就需要将所有的数都存储在内存中,这会消耗大量的内存空间。
my_list = list(range(1, 1000001))
然而,如果我们使用迭代器来生成这个数列,只需要在需要使用时逐个生成数字,而不需要一次性存储全部数字。这节省了大量的内存空间。
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)
过使用迭代器,我们避免了一次性将所有数字存储在内存中的需求,减少了内存的占用。相比之下,使用列表则需要先生成并存储所有数字,会占用大量的内存。
此外,迭代器还具有惰性求值的特点,即只在需要时才生成下一个元素。这种特性在处理大量数据时非常有用,可以减少不必要的计算和处理时间。
因此,使用迭代器可以节省内存,并在处理大量数据时提高性能。它们可以逐个生成序列中的元素,而无需一次性将所有元素存储在内存中。
最后
通过上述例子,可以知道实现了方法__iter__
的对象是可迭代的,而实现了方法__next__
的对象是迭代器。
以上就是Python中的迭代器详解的详细内容,更多关于Python迭代器的资料请关注脚本之家其它相关文章!