__iter__
方法返回非迭代器¶
ID: py/iter-returns-non-iterator
Kind: problem
Security severity:
Severity: error
Precision: high
Tags:
- reliability
- correctness
Query suites:
- python-security-and-quality.qls
类的 __iter__
方法应始终返回迭代器。
对于 Python 3,迭代器必须同时实现 __next__
和 __iter__
,对于 Python 2,迭代器必须同时实现 next
和 __iter__
。迭代器的 __iter__
方法必须返回迭代器对象本身。
Python 中的迭代依赖于这种行为,尝试迭代具有不正确的 __iter__
方法的类的实例可能会引发 TypeError
。
建议¶
确保 __iter__
返回的值实现了完整的迭代器协议。
示例¶
在这个示例中,我们实现了我们自己的 range
版本,扩展了正常的功能,可以通过使用 skip
方法来跳过一些元素。但是,迭代器 MyRangeIterator
并没有完全实现迭代器协议(即它缺少 __iter__
)。
在表面上,对范围中的元素进行迭代似乎有效,例如代码 x = sum(my_range)
给出了预期的结果。但是,如果我们运行 sum(iter(my_range))
,我们会得到一个 TypeError: 'MyRangeIterator' object is not iterable
。
如果我们尝试使用自定义方法跳过一些元素,例如 y = sum(my_range.skip({6,9}))
,这也会引发 TypeError
。
解决方法是在 MyRangeIterator
中实现 __iter__
方法。
class MyRange(object):
def __init__(self, low, high):
self.low = low
self.high = high
def __iter__(self):
return MyRangeIterator(self.low, self.high)
def skip(self, to_skip):
return MyRangeIterator(self.low, self.high, to_skip)
class MyRangeIterator(object):
def __init__(self, low, high, skip=None):
self.current = low
self.high = high
self.skip = skip
def __next__(self):
if self.current >= self.high:
raise StopIteration
to_return = self.current
self.current += 1
if self.skip and to_return in self.skip:
return self.__next__()
return to_return
# Problem is fixed by uncommenting these lines
# def __iter__(self):
# return self
my_range = MyRange(0,10)
x = sum(my_range) # x = 45
y = sum(my_range.skip({6,9})) # TypeError: 'MyRangeIterator' object is not iterable
参考¶
Python 语言参考:object.iter.
Python 标准库:迭代器类型.