为何__iter__返回非迭代器会触发Traceback?代码示例解析
为什么__iter__返回字符串会触发TypeError?
错误原因
Python的迭代器协议有明确硬性要求:__iter__方法必须返回一个迭代器对象,而不是普通的可迭代对象(比如字符串、列表)或者其他非迭代器类型。
那到底什么是迭代器对象?它得同时满足两个条件:
- 实现了
__iter__方法,并且返回自身(保证迭代器本身也能被迭代) - 实现了
next()方法(Python 3中是__next__()),用来返回下一个元素,当没有元素可返回时抛出StopIteration异常
而字符串只是可迭代对象,不是迭代器——你可以用iter("my string")把它转成迭代器,但它本身没有next()方法,完全不符合迭代器的标准。
Python何时检测返回对象是否为迭代器?
当你调用iter()函数(或者在for循环、列表推导等场景中隐式调用iter()时),Python会按这个流程执行:
- 调用目标对象的
__iter__方法,拿到返回值 - 立刻检查这个返回值是否是合法迭代器:核心就是确认它有没有
next()(Python2)/__next__()(Python3)方法,且能正常调用 - 如果返回的对象不满足迭代器要求,就直接抛出你看到的
TypeError: iter() returned non-iterator of type 'str'错误
怎么修复这个问题?
有两种简单的修复方式:
方式1:返回字符串对应的迭代器
直接用iter()把字符串转成合法的迭代器返回就行:
class test(object): def __init__(self): pass def __iter__(self): return iter("my string") # 转成迭代器返回 o = test() print iter(o)
运行后会输出类似<iterator object at 0x10xxxxxx>的结果,这就是符合要求的迭代器对象。
方式2:自定义迭代器类
如果需要更灵活的迭代逻辑,可以自己实现一个符合迭代器协议的类,让__iter__返回这个类的实例:
class StringIterator(object): def __init__(self, s): self.string = s self.pos = 0 def __iter__(self): return self def next(self): # Python3请改为__next__ if self.pos >= len(self.string): raise StopIteration char = self.string[self.pos] self.pos += 1 return char class test(object): def __iter__(self): return StringIterator("my string") o = test() print iter(o)
这样返回的就是完全符合协议要求的自定义迭代器对象。
内容的提问来源于stack exchange,提问作者Ankur Agarwal
相关产品推荐
相关产品推荐

