生成器函数yield

先看一个栗子:

# -*- coding:UTF-8 -*-
__autor__ = 'zhouli'
__date__ = '2018/12/6 21:08'


# 生成器函数,函数里只要有yield关键字

def gen_func():
    yield 1


def func():
    return 1


if __name__ == "__main__":
    gen = gen_func()
    re = func()
    pass

生成器函数这个对象是是什么时候产生的呢?是python编译字节码的时候就产生了,

既然是生成器对象,那么一定可以使用for循环进行遍历,并且yield可以多次

def gen_func():
    yield 1
    yield 2
    yield 3
    yield 4

yield的特性:惰性求值, 延迟求值提供了可能

斐波那契数列的经典举例:

def fib(index):
    if index <= 2:
        return 1
    else:
        return fib(index-1) + fib(index-2)
print(fib(10))

这样虽然可以做出来,但是没有具体的过程,那改进一下

def fib2(index):
    relist = []
    n,a,b = 0,0,1
    while n<index:
        relist.append(b)
        a, b = b, a+b
        n += 1
    return relist

假如说现在index很大,上亿,那内存就有可能不够了。

def fib2(index):
    n,a,b = 0,0,1
    while n<index:
        yield b
        a, b = b, a+b
        n += 1

改成这样,内部没有维护一个列表,自然而然就不会消耗内存的

当然这样可以直接进行for循环了

那生成器的原理是什么呢?适用于什么场景呢?如何区别于函数呢?

def foo():
    bar()


def bar():
    global frame
    frame = inspect.currentframe()


# python.exe会用一个叫做 PyEval_EvalFramEx(c函数)去执行foo函数, 首先会创建一个栈帧(stack frame)
python一切皆对象,栈帧对象, 字节码对象
当foo调用子函数 bar, 又会创建一个栈帧
所有的栈帧都是分配在堆内存上,这就决定了栈帧可以独立于调用者存在

利用生成器表达式读取大文件:

有人可能讲了,for line in f.open()

但是如果只有一行呢?

f.read(4096)  # 先读4096个字符
f.read(4096)  # 自动再次读取4096个字符
# 500G, 特殊 一行
def myreadlines(f, newline):
    buf = ""
    while True:
        while newline in buf:
            pos = buf.index(newline)
            yield buf[:pos]
            buf = buf[pos + len(newline):]
        chunk = f.read(4096)

        if not chunk:
            # 说明已经读到了文件结尾
            yield buf
            break
        buf += chunk


with open("input.txt") as f:
    for line in myreadlines(f, "{|}"):
        print(line)

猜你喜欢

转载自www.cnblogs.com/zhoulixiansen/p/10080183.html