伪代码
可迭代对象(Iterable)
例如 list、tuple、set、str 等,它们每次调用 iter(x) 都会新建一个独立的迭代器,所以可以被反复遍历。
每次被 iter() 调用就生成一个新的迭代器实例。
class list: # 伪代码 def __iter__(self): # 新建一个专属的 list_iterator,把当前列表引用塞进去 return list_iterator(self) def __getitem__(self, idx): ... # 正常按下标访问元素 下面用“伪代码”把 list 在 CPython 里“怎么做到多次迭代”的核心机制画出来。 真正的代码在 C 里(Objects/listobject.c),但逻辑可以这么理解: ---- 1. 可迭代对象(list)只干一件事: 每次被 iter() 调用就生成一个新的迭代器实例。 class list: # 伪代码 def __iter__(self): # 新建一个专属的 list_iterator,把当前列表引用塞进去 return list_iterator(self) def __getitem__(self, idx): ... # 正常按下标访问元素 ---- 2. 迭代器(list_iterator)才记住“我走到哪了”: class list_iterator: def __init__(self, lst): # lst 就是外面的那个 list 对象 self.lst = lst # 保留对列表的引用 self.index = 0 # 只有我自己拥有的游标 def __iter__(self): return self # 协议要求 def __next__(self): if self.index >= len(self.lst): raise StopIteration val = self.lst[self.index] # 去真正的列表里拿元素 self.index += 1 return val ---- 3. 使用场景拆解 >>> nums = [10, 20, 30] # 这是一个可迭代对象 >>> it1 = iter(nums) # 第一次:list.__iter__() 返回新的 list_iterator >>> it2 = iter(nums) # 第二次:又返回一个全新的 list_iterator >>> next(it1) 10 >>> next(it2) # it2 从 0 开始,不受 it1 影响 10 • nums 本身没有任何“游标”状态,所以可以被无限次 iter()。 • 真正消耗迭代进度的是 list_iterator 里的 index 字段; 每次 for x in nums: 都会拿到一个崭新的 list_iterator,于是又能从头再来。 ---- 4. 小结一句话 “可迭代对象”只负责生迭代器; “迭代器”才负责记进度; 把“生迭代器”和“记进度”拆成两个对象,就天然支持了“多次迭代”。