Python函数生成器原理及使用详解


Posted in Python onMarch 12, 2020

1.python函数运行原理

import inspect
frame = None
def foo():
  bar()


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

# python解释器 python.exe 会用一个叫做PyEval_EvalFrameEx(c语言函数)去执行foo函数,首先会创建一个栈帧(stack frame),
"""
python在运行前会编译成字节码对象
当foo调用bar函数进,又会创建一个栈帧,
关键是所有的栈帧都是分配在堆内存, 堆内存有个特点,不手动释放,就会一直存在
这就决定了栈帧可以独立于调用者存在.

"""

# import dis
# print(dis.dis(foo)) # 查看foo函数的字节码


foo() #先调用一下foo函数 ,这个frame就有值.

print(frame.f_code.co_name) # bar  查看这个栈帧, bar 所以还是可以拿到bar的栈帧,然后就可以调用bar函数

caller_frame = frame.f_back # 当前frame栈帧的调用者的栈帧
print(caller_frame.f_code.co_name) # foo , 也可以拿到bar函数的栈帧

python中函数的调用就是创建栈帧的过程,而这些创建的栈帧都是存放在堆上面,不释放就永久存在,所以我们拿到每个函数对应的栈帧,就可以调用这个函数.

java就不行了,函数执行完毕,直接弹栈完蛋.

Python函数生成器原理及使用详解

2.生成器执行原理

测试代码

def gen_fun():
  yield 1
  name = 'admin'
  yield 2
  gender = 'male'
  return 3

看看测试代码对应的字节码文件

0 LOAD_CONST        1 (1)
YIELD_VALUE
POP_TOP
     6 LOAD_CONST        2 ('admin')
STORE_FAST        0 (name)
     10 LOAD_CONST        3 (2)
YIELD_VALUE
POP_TOP
     16 LOAD_CONST        4 ('male')
STORE_FAST        1 (gender)
     20 LOAD_CONST        5 (3)
RETURN_VALUE
None

测试gi_frame

# 在没有执行生成器时
print(gen.gi_frame.f_lasti) # -1 ,在没有调用next方法迭代时,f_lasti 等于-1, 表示还没开始呢
print(gen.gi_frame.f_locals) # {}

# 执行第一行
next(gen)

print(gen.gi_frame.f_lasti) # 2  # 执行一行next后,代码停在了第二行,看上面字节码文件
print(gen.gi_frame.f_locals) # {}

# 再执行一次
next(gen)

print(gen.gi_frame.f_lasti) # 12 # 又执行一次next之后,程序停在了12行
print(gen.gi_frame.f_locals) # {'name': 'admin'}

由上面的测试代码可以知道,在生成器的gi_frame对象中维护着两个重要的属性f_lasti和f_locals.

f_lasti记录着当前代码运行到哪一行了(注意这里的那一行是指编译之后的字节码文件)

f_locals维护着当前生成器中的属性字段

有了这两个属性,生成器就知道下一次next从哪儿开始执行了....

Python函数生成器原理及使用详解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python多线程编程(五):死锁的形成
Apr 05 Python
python制作最美应用的爬虫
Oct 28 Python
Python内置函数delattr的具体用法
Nov 23 Python
Django重装mysql后启动报错:No module named ‘MySQLdb’的解决方法
Apr 22 Python
对Python中创建进程的两种方式以及进程池详解
Jan 14 Python
通过实例解析python描述符原理作用
Jan 22 Python
python使用ctypes调用扩展模块的实例方法
Jan 28 Python
基于Python实现人脸自动戴口罩系统
Feb 06 Python
python如何通过闭包实现计算器的功能
Feb 22 Python
Python打印特殊符号及对应编码解析
May 07 Python
Python调用C/C++的方法解析
Aug 05 Python
python实现启动一个外部程序,并且不阻塞当前进程
Dec 05 Python
python deque模块简单使用代码实例
Mar 12 #Python
python中安装django模块的方法
Mar 12 #Python
python3 sorted 如何实现自定义排序标准
Mar 12 #Python
Python dict和defaultdict使用实例解析
Mar 12 #Python
Python数据结构dict常用操作代码实例
Mar 12 #Python
Python基于类路径字符串获取静态属性
Mar 12 #Python
对python中return与yield的区别详解
Mar 12 #Python
You might like
MySQL数据源表结构图示
2008/06/05 PHP
PHP实现将多个文件压缩成zip格式并下载到本地的方法示例
2018/05/23 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式二图文详解
2019/04/09 PHP
laravel 如何实现引入自己的函数或类库
2019/10/15 PHP
表格 隔行换色升级版
2009/11/07 Javascript
jquery对表单操作2
2011/04/06 Javascript
web开发人员学习jQuery的6大理由及jQuery的优势介绍
2013/01/03 Javascript
JavaScript实现网页上的浮动广告的简单方法
2013/06/14 Javascript
JS window对象的top、parent、opener含义介绍
2013/12/03 Javascript
jquery ajax 局部刷新小案例
2014/02/08 Javascript
JavaScript中标识符提升问题
2015/06/11 Javascript
js实现创建删除html元素小结
2015/09/30 Javascript
BootStrap 实现各种样式的进度条效果
2016/12/07 Javascript
基于JavaScript实现随机颜色输入框
2016/12/10 Javascript
解析NodeJs的调试方法
2016/12/11 NodeJs
jquery使用EasyUI Tree异步加载JSON数据(生成树)
2017/02/11 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
express框架实现基于Websocket建立的简易聊天室
2017/08/10 Javascript
JavaScript中使用Async实现异步控制
2017/08/15 Javascript
vue基于Element构建自定义树的示例代码
2017/09/19 Javascript
vue+elementUI实现表格关键字筛选高亮
2020/10/26 Javascript
[05:09]2016国际邀请赛中国区预选赛淘汰赛首日精彩回顾
2016/06/29 DOTA
[44:30]完美世界DOTA2联赛PWL S2 GXR vs Magma 第一场 11.25
2020/11/26 DOTA
Python中的文件和目录操作实现代码
2011/03/13 Python
更换Django默认的模板引擎为jinja2的实现方法
2018/05/28 Python
python实现雨滴下落到地面效果
2018/06/21 Python
python 地图经纬度转换、纠偏的实例代码
2018/08/06 Python
python正则表达式匹配[]中间为任意字符的实例
2018/12/25 Python
详解Python3注释知识点
2019/02/19 Python
深入研究HTML5实现图片压缩上传功能
2016/03/25 HTML / CSS
HTML5 Canvas锯齿图代码实例
2014/04/10 HTML / CSS
移动端开发HTML5页面点击按钮后出现闪烁或黑色背景的解决办法
2018/09/19 HTML / CSS
Goodee官方商店:迷你投影仪
2021/03/15 全球购物
精彩的推荐信范文
2013/11/26 职场文书
归途列车观后感
2015/06/17 职场文书
新闻稿格式范文
2015/07/18 职场文书