python中生成器

生成器是根据算法生成数据的一种机制,每次调用生成器只生成一个值,可以节省大量内存

生成器推导式

python 复制代码
gg = ( i * 2 for i in  range(5))

print(gg)

print(next(gg)) # 0
print(next(gg)) # 2
print(next(gg)) # 4
print(next(gg)) # 6
print(next(gg)) # 8

yield关键字

python 复制代码
def generater(num):
    for i in range(num):
        print("开始")
        yield i
        print("生成完成")

g = generater(2)

print( next(g) )
print( next(g) )
print( next(g) )

"""
开始
0
生成完成
开始
1
生成完成
Traceback (most recent call last):
  File "d:\Code\PythonProject\with\Generator2.py", line 11, in <module>
    print( next(g) )
           ^^^^^^^
StopIteration
"""
python 复制代码
def generater(num):
    for i in range(num):
        print("开始")
        yield i
        print("生成完成")

g = generater(5)


for i in g:
    print(i)
"""
不会报错
"""

生成器的核心思想是​​惰性计算​​。它不会一次性把所有数据都计算出来并存储在内存中,而是"需要的时候才计算,每次只给你一个"。

假设有一个几十GB的日志文件,你需要逐行处理。

python 复制代码
def read_file_to_list(filename):
    result = [] # 创建一个空列表
    with open(filename) as f:
        for line in f:
            result.append(line) # 将每一行都添加到列表中
    return result # 返回一个包含所有行的巨大列表

data = read_file_to_list('huge_log.log') # 内存爆炸!
for line in data:
    process(line)

​问题​ ​:result列表会尝试将所有文件内容加载到内存中,如果文件极大,会消耗巨量内存甚至导致程序崩溃。

python 复制代码
def read_file_by_line(filename):
    with open(filename) as f:
        for line in f: 
            yield line # 关键在这里:使用yield

data_generator = read_file_by_line('huge_log.log') # 几乎不占内存
for line in data_generator: # 每次循环从文件里读一行到内存
    process(line)
  1. 调用read_file_by_line时候,函数不会立即执行,而是返回一个生成器对象,此时文件一行都没读

  2. 在for循环中,每次迭代会从生成器中请求一个值(一行内容)

  3. 生成器函数从上次暂停的yield处继续执行,读取文件的下一行,yield返回这行数据,然后立即暂停。