迭代器
-
什么是迭代器
- 迭代器是类序列的接口。迭代器不是序列但表现出序列行为的对象, 例如: 字典的键、文件的行等等
-
为什么要迭代器
- 提供了可扩展的迭代器接口
- 对列表迭代带来了性能上的增强
- 在字典迭代中性能提升
- 创建真正的迭代接口,而不是原来的随机对象访问
- 与所有已经存在的用户定义的类以及扩展的模拟序列和映射的对象后兼容
- 迭代非序列集合时,可以创建更简洁可读的代码
-
如何迭代
-
迭代器就是一个有 next() 方法的对象,而不是通过索引来计数。当你或一个循环机制需要下一个项时,调用迭代器的 next() 方法就可以获得它条目全部取出后,会引发一个 StopIteration 异常,这并不是表示错误发生,只是告诉外部调用者,迭代完成
-
for 循环迭代: for 循环会自动调用迭代器的 next() 方法,以及键时 StopInteration 异常
for in seq: do_something_to(i) # 实际上是这样工作的: fetch = iter(seq) while True: try: i = fetch.next() expect StopIteration: break do_something_to(i)
-
-
迭代器的限制
- 不能向后移动,不能回到开始,也不能复制一个迭代器
- 如果想要再次迭代同个对象,只能取创建另一个迭代器对象
-
可变对象和迭代器
- 一个序列的迭代器只是记录当前迭代到达第多少个元素,所以如果你在迭代是改变了元素,会更新立即反应到你所迭代的条目上
- 在迭代一个字典的键时,你绝对不能改变这个字典。使用字典的 keys() 方法是可以的。因为 keys() 方法返回一个独立的字典的键列表。而迭代器与实际对象绑定在一起,不会继续执行下去
-
如何创建迭代器
-
对一个对象调用 iter() 方法就可以得到它的迭代器;
- 如: iter(obj), iter(func, sentinel)
-
如果传递一个参数给 iter() ,它会检查你传递的是不是一个序列,如果是,则根据索引从 0 一致迭代到序列结束。
-
另一个创建迭代器的方法是实用类,一个实现了 iter() 和 next() 方法的类可以作为迭代器使用。
-
如果传递两个参数给 iter() ,它会重复的调用 func,直到迭代器的下一个值等于 sentinel
-
生成器表达式
-
生成器表达式是列表解析的扩展
- 列表解析的一个不足就是必要生成所有的数据,用以创建整个列表。这可能对有大量数据的迭代器有负面效应。
- 生成器表达式通过结合列表解析和生成器解决了这个问题
-
生成器表达式和列表解析非常相似,但是它并不会真正的创建数字列表,而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目"产生"(yield)出来。
-
生成器表达式使用了"延迟计算",所以它在使用内存上更有效
-
生成器并不会让列表解析废弃,它只是一个内存使用更友好的结构
-
生成器表达式和列表解析:
- 列表解析: [expr for iter_var in iterable if code_expr]
- 生成器表达式: (expr for iter_var in iterable if code_expr)