Python面试_可迭代对象&迭代器&生成器

生成器

生成器函数

  • 生成器函数:函数体内有yield关键字
  • 函数返回值:生成器对象
  • 函数执行顺序:在生成器对象每次调用next()时执行,遇到yield语句返回,再次调用执行时从上次返回的yield语句处继续执行
def generator_func():
    print("step 1")
    yield 1
    print("step 2")
    yield 2
    print("step 3")
    yield 3


def normal_func():
    return 1


if __name__ == '__main__':
    g = generator_func()  # <generator object generator_func at 0x7ff0908cade0>
    n = normal_func()  # n: 1
    # print(dis.dis(generator_func))
    for i in g:
        print("generator obj res: ", i)

"""
step 1
generator obj res:  1
step 2
generator obj res:  2
step 3
generator obj res:  3
"""

函数执行

从下面的例子中,让我们来了解函数的执行过程:

import inspect

frame = None


def foo():
    bar()


def bar():
    global frame
    frame = inspect.currentframe()  # 返回当前栈帧对象


foo()
print(frame.f_code.co_name)  # 打印栈帧对象名 --> bar
caller_frame = frame.f_back  # 获取调用栈帧对象
print(caller_frame.f_code.co_name)  # 打印调用栈帧对象名 --> foo

python中函数调用的执行过程:
1)python.exe会通过C实现的函数:PyEval_EvalFrameEx()去执行定义的Python foo()函数

  • 首先会创建一个栈帧对象(FrameObject)
  • 栈帧对象会去执行foo()函数的Python字节码

2)当执行到调用bar()函数时

  • 会再创建一个栈帧对象(FrameObject)
  • 新的栈帧对象会去执行bar()函数的Python字节码

流程如图:
image.png
Python中函数的调用类似递归的过程,所有的堆栈对象都分配在堆内存上(不会随着函数执行完而销毁),这就决定了堆栈对象可以独立于调用者而存在。

生成器函数执行

CPython解释器在编译Python字节码时就会生产生成器对象,C函数PyEval_EvalFrameEx()会在堆栈对象的基础上进行封装为生成器对象(PyGenObject),生成器对象(PyGenObject),gi_frame指向一个新的PyFrameObject,其中保存了生成器对象上次执行的字节码位置(f_lasti),而gi_code则指向PyCodeObject用于保存生成器函数的字节码。

image.png

通过一个例子来看看其具体过程,首先通过dis来打印出生成器函数的Python字节码:

def generator_func():
    yield 1
    name = "zgt"
    yield 2
    age = 18
    return "hello generator"


print(dis.dis(generator_func))

image.png
再通过next()函数来执行生成器对象,并打印其堆栈对象中内容:

g = generator_func()
print(g.gi_frame.f_lasti)   # -1
print(g.gi_frame.f_locals)  # {}

next(g)
print(g.gi_frame.f_lasti)   # 2
print(g.gi_frame.f_locals)  # {}

next(g)
print(g.gi_frame.f_lasti)   # 12
print(g.gi_frame.f_locals)  # {'name':'zgt'}

对比生成器函数的字节码,我们就可以理解Python的生成器的独特aazA处(延时求值)的实现原理。

posted @ 2023-02-09 15:16  ZZGGTT  阅读(43)  评论(0编辑  收藏  举报