Python中.__iter__()与iter()是否等同?PyTorch迭代器疑惑
关于Python中__iter__()与iter()的差异问题
问题背景
在学习PyTorch DataLoader时遇到迭代器相关疑惑,通过两组代码实验说明:
第一组代码
class a: def __init__(self): self.l = [1,2,3,4] def __iter__(self): return self.l cls_a = a() # 1. 正常运行 for c in cls_a.__iter__(): print(c) # 2. 报错:TypeError: iter() returned non-iterator of type 'list' for c in iter(cls_a): print(c)
第二组代码
l = [1,2,3,4] # 3. 正常运行 for c in l.__iter__(): print(c) # 4. 正常运行 for c in iter(l): print(c)
核心疑问:iter(cls_a)与iter([1,2,3,4])表现不同,想明确__iter__()与iter()的差异。
原因解析
1. 先明确两个核心概念
- 可迭代对象(Iterable):实现
__iter__()方法(返回迭代器),或实现__getitem__()且索引从0开始的对象,比如列表、元组。 - 迭代器(Iterator):同时实现
__iter__()(返回自身)和__next__()(返回下一个元素,无元素时抛StopIteration)的对象,是真正能被next()调用取值的对象。
2. 自定义类a的问题
你的自定义类a的__iter__()方法返回的是列表(可迭代对象),而不是迭代器对象,违反了Python的迭代器协议。
当调用iter(cls_a)时,内置函数iter()会执行以下逻辑:
- 调用
cls_a.__iter__()得到返回值(即列表self.l) - 检查该返回值是否是迭代器:列表不是迭代器,因此直接抛出
TypeError。
而代码1中直接调用cls_a.__iter__()得到列表后,for循环会自动对这个列表调用iter(),生成合法的迭代器,因此能正常运行。
3. 内置列表的__iter__()行为
内置列表的__iter__()方法返回的是专门的迭代器对象(如list_iterator),而不是列表本身。因此:
- 代码3中
l.__iter__()直接返回迭代器,for循环可以直接用; - 代码4中
iter(l)调用l.__iter__()得到合法迭代器,自然也能正常运行。
4. __iter__()与iter()的核心差异
- 直接调用
x.__iter__():仅执行对象自身定义的__iter__()方法逻辑,返回方法指定的对象,不会做额外校验。即使返回的不是迭代器,后续如果有逻辑(比如for循环)自动处理可迭代对象,也能正常运行。 - 调用
iter(x):是Python内置的标准化迭代器生成函数,逻辑更严格:- 优先调用
x.__iter__(),若返回值是迭代器则直接返回; - 若
x没有__iter__()但有__getitem__(),则自动生成一个基于索引遍历的迭代器; - 若以上都不满足,或
__iter__()返回非迭代器对象,则抛出TypeError。
- 优先调用
内容的提问来源于stack exchange,提问作者ehuang98
相关产品推荐
相关产品推荐

