迭代器

原理非常类似Lua的泛型for。

  1. for v in shit:
  2. print v
  3. #for的幕后逻辑如下;
  4. iterable = iter(shit) #生成对象的迭代器:iter()内置函数放回一个定义了__next__()方法的迭代对象
  5. v = next(iterable) #进行迭代:next()内置函数会调用__next__方法返回迭代数据。
  6. #当迭代完了,next会抛出StopIteration的异常来终止for循环。
  7. #了解了for的幕后逻辑,我们可以自定义可迭代对象,而不仅限于使用内置类型。
  8. class IterableObj:
  9. """文档说明字符串"""
  10. def __init__(self, data):
  11. self.data = data
  12. self.index = len(data)
  13. def __iter__(self): #iter(obj)触发并返回值
  14. return self
  15. def __next__(self): #next(obj)触发并返回值
  16. if self.index == 0:
  17. raise StopIteration
  18. self.index = self.index - 1
  19. return self.data[self.index]
  20. obj = IterableObj([1, 2, 3, 4, 5])
  21. for v in obj:
  22. print(v)
  23. #5
  24. #4
  25. #3
  26. #2
  27. #1

生成器:yield

Generator,用于生成迭代器。写法类似函数,但当它们要返回数据时会使用 yield 语句,yield的效果就是每次next(生成器)时,就会从上次离开位置回复执行。
相比于上面手写迭代器,本质上就是自动完成了这些工作:

  • 自动创建方法
    • iter() 和 next() 方法。
  • 保存程序状态
    • 类似lua的闭包
  • 自动引发stopIteration

所以利用生成器,可以大大简化生成迭代器的工作。

  1. def reverse(data):
  2. for index in range(len(data)-1, -1, -1):
  3. yield data[index]
  4. for char in reverse('golf'):
  5. print(char)

生成器表达式

类似列表推导式。

  1. sum(i*i for i in range(10)) #285
  2. xvec = [10, 20, 30]
  3. yvec = [7, 5, 3]
  4. sum(x*y for x,y in zip(xvec, yvec)) #260
  5. from math import pi, sin
  6. sine_table = {x: sin(x*pi/180) for x in range(0, 91)}
  7. unique_words = set(word for line in page for word in line.split())
  8. valedictorian = max((student.gpa, student.name) for student in graduates)
  9. data = 'golf'
  10. list(data[i] for i in range(len(data)-1, -1, -1)) #['f', 'l', 'o', 'g']