今天我们来聊一个Python面试中老生常谈但总有人会磕巴的问题:“谈谈你对迭代器和生成器的理解。”很多人面试时一听到这个问题,第一反应就是开始在脑子里检索迭代器和生成器的概念,试图搬出几个关键字让自己显得专业。
但面试官要的是你的理解,而不是关键词的堆砌。所以今天我们就来聊聊,怎么样把“迭代器和生成器”这道题讲得既通俗又有深度,争取给面试官留下好印象。
首先,我们来看看迭代器。要理解迭代器,先得知道Python的迭代协议。Python中,并没有特意为“协议”设计关键字,像interface
、protocol
这类字眼压根就不在Python的语法里。
Python讲究“约定优于配置”,说白了,大家都遵守一套规则,这套规则就默认成了“协议”。而迭代器的“协议”主要靠两个魔法方法:__iter__
和__next__
。这两个方法就是迭代器对象的核心。
在Python中,凡是实现了__iter__()
和__next__()
的对象就可以称为迭代器。简单点说,__iter__()
用来返回迭代器本身,而__next__()
用来返回迭代器的下一个值。来看个例子:
class MyIterator:
def __init__(self, max):
self.max = max
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current < self.max:
self.current += 1
return self.current - 1
raise StopIteration()
在这个类里,__iter__
返回了迭代器本身,也就是说我们每次循环时可以继续从当前值开始。__next__
则返回当前的值并增加1,直到达到max
时抛出StopIteration
异常,结束迭代。抛出StopIteration
是一种标准写法,告诉for
循环“到此为止”。
迭代器的设计可以让我们从数据集合中逐个获取元素,而不需要先把整个数据加载到内存中。这点在处理大数据的时候特别实用。举个简单例子,假如你要处理一个巨大的文件,把每一行都读进来显然很不实际,而通过迭代器可以实现一行一行地读取,非常高效。
再来说生成器。生成器是Python里对迭代器的“轻量版”升级。其实我们也可以理解为生成器是“语法糖”版的迭代器。它的好处是代码简洁,不需要写__iter__()
和__next__()
方法。只要在函数里使用yield
,Python就会自动把这个函数转换成一个生成器。
举个例子,假设我们要写一个生成斐波那契数列的代码,用迭代器和生成器的差别就非常明显。
# 迭代器实现斐波那契数列
class Fibonacci:
def __init__(self, n):
self.n = n
self.current = 0
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
if self.current < self.n:
value = self.a
self.a, self.b = self.b, self.a + self.b
self.current += 1
return value
raise StopIteration()
这个迭代器的逻辑很清楚,但代码量确实稍多了一点儿。我们需要自己去定义状态变量self.a
和self.b
,而且还要手动抛出StopIteration
。
来看一下生成器版本:
# 生成器实现斐波那契数列
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
只用几行代码,我们就实现了同样的功能。生成器函数的优势就在于它不需要自己管理状态或异常,yield
每次都会暂停函数的执行,保存当前的状态,并且在下一次调用时恢复运行。可以说,生成器是写迭代器的一条“捷径”。
大家可能会好奇,这俩有啥区别?我总结了以下几点:
语法层面:迭代器需要实现 __iter__
和__next__
方法,而生成器则直接用yield
语句省去了这些麻烦。内存效率:生成器每次只在需要时生成数据,而不一次性加载到内存中。假如我们要生成一个长度为百万级的数据序列,生成器的节省效果相当可观。 实现简单:用生成器实现逻辑简单的生成过程只需几行代码,而迭代器实现往往需要定义类、初始化变量等,代码相对繁琐。
回到面试现场,当面试官问到迭代器和生成器的区别时,我觉得可以这么答:
迭代器是通过实现
__iter__
和__next__
方法来逐个生成数据的对象,可以手动定义类来实现;生成器则是迭代器的一种简化形式,利用yield
关键字更简洁地返回数据,特别适合用于内存高效的场景。
好了,今天的分享就到这里,那么大家怎么看呢?欢迎评论区留言分享!
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
资料包含了《IDEA视频教程》、《最全python面试题库》、《最全项目实战源码及视频》及《毕业设计系统源码》,总量高达650GB。全部免费领取!全面满足各个阶段程序员的学习需求。