迭代器:
使用迭代器的一个好处是为列表类型的对象提供一个统一的遍历接口,即next方法。另一个好处是提高内存利用率。比如需要读取并且遍历一个很大的文本文件,如果使用列表解析,系统会将整个文件的内容先放入内存,然后再进行处理,对内存大小要求较高。而使用迭代器,每次只会取出文件中的一条记录放入内存,因此可以提高内存的使用效率。
生成器:
生成器相对于迭代器可以进一步对代码进行简化。
以查找一个文本文件中最长的一条记录为例,介绍迭代器的好处。
''' 不使用迭代器,逐条遍历后处理 多线程情况下,会长时间占用文件,并发性低 ''' def func1(file_name): f = open(file_name) max_length = 0 while True: temp_len = len(f.readline().strip()) if not temp_len: break if temp_len > max_length: max_length = temp_len f.close() return max_length ''' 一次性读取整个文件后,关闭文件然后使用迭代器遍历 文件很大时,需要将整个文件内容加载到内存,内存使用率低下 ''' def func2(file_name): f = open(file_name) text = f.readlines() f.close() max_length = 0 for line in text: temp_len = len(line) if temp_len > max_length: max_length = temp_len return max_length ''' 只将文件中的所有行的长度列表化,然后遍历长度列表查找最长的行 只需要将文件中的所有行的长度加载到内存,内存使用率比fun2()高 文件遍历过程,处理步骤较简单,并发性比func1()高 ''' def func3(file_name): f = open(file_name) len_list = [len(line) for line in f] f.close() max_length = 0 for temp_len in len_list: if temp_len > max_length: max_length = temp_len return max_length ''' 使用生成器,代码比func3()更加简洁 max()方法的参数不仅仅可以是列表,也可以是一个可迭代对象,如迭代器和生成器 ps: [len(line) for line in f] 生成一个普通的列表 len(line) for line in f 为生成器表达式,产生生成器,与上式的区别仅仅是去掉了中括号 ''' def func4(file_name): f = open(file_name) max_length = max(len(line) for line in f.readline()) f.close() return max_length
下面再介绍生成斐波那契数列的例子,说明生成器相对应迭代器的好处。
''' 从1开始,生成长度为maxNum个斐波那契数 使用迭代器 ''' class Fabs(object): def __init__(self, maxNum): self.max = maxNum self.n, self.a, self.b = 0, 0, 1 #特别指出:第0项是0,第1项是第一个1.整个数列从1开始 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration() ''' 从1开始,生成长度为maxNum个斐波那契数 使用生成器,与使用迭代器相比,不需要重写各种方法,代码更简洁 ''' def fab(maxNum): n, a, b = 0, 0, 1 while n < maxNum: yield b a, b = b, a + b n = n = 1
下面的链接介绍了一个使用生成器自定义contextManager装饰器的例子,是对装饰器和生成器的一个综合应用,可以更好地帮助理解上下文管理器、装饰器以及生成器。