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 相关文章推荐
linux下安装easy_install的方法
Feb 10 Python
Python中使用第三方库xlrd来写入Excel文件示例
Apr 05 Python
简单介绍Python中的readline()方法的使用
May 24 Python
Python的Django框架安装全攻略
Jul 15 Python
python+django加载静态网页模板解析
Dec 12 Python
Tensorflow卷积神经网络实例
May 24 Python
python高阶爬虫实战分析
Jul 29 Python
python字符串替换第一个字符串的方法
Jun 26 Python
Python实现个人微信号自动监控告警的示例
Jul 03 Python
Django 返回json数据的实现示例
Mar 05 Python
Python venv虚拟环境配置过程解析
Jul 08 Python
解决numpy数组互换两行及赋值的问题
Apr 17 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
PHP编程基本语法快速入门手册
2016/01/07 PHP
PHP使用自定义方法实现数组合并示例
2016/07/07 PHP
Laravel用户授权系统的使用方法示例
2018/09/16 PHP
4种Windows系统下Laravel框架的开发环境安装及部署方法详解
2020/04/06 PHP
jQuery 锚点跳转滚动条平滑滚动一句话代码
2010/04/30 Javascript
改进UCHOME的记录发布,增强可访问性用户体验
2011/01/17 Javascript
jQuery中调用WebService方法小结
2011/03/28 Javascript
js中的如何定位固定层的位置
2014/06/15 Javascript
js的[defer]和[async]属性
2014/11/24 Javascript
javascript引用赋值(地址传值)用法实例
2015/01/13 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
2015/12/22 Javascript
vue-axios使用详解
2017/05/10 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
vue.js如何将echarts封装为组件一键使用详解
2017/10/10 Javascript
JS面试题大坑之隐式类型转换实例代码
2018/10/14 Javascript
vue.js实现的全选与全不选功能示例【基于elementui】
2018/12/03 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
浅谈Vue项目骨架屏注入实践
2019/08/05 Javascript
关于vue2强制刷新,解决页面不会重新渲染的问题
2019/10/29 Javascript
如何解决jQuery 和其他JS库的冲突
2020/06/22 jQuery
解决vue+elementui项目打包后样式变化问题
2020/08/03 Javascript
[01:53]DOTA2超级联赛专访Zhou 五年职业青春成长
2013/05/29 DOTA
Python删除指定目录下过期文件的2个脚本分享
2014/04/10 Python
Python 获得13位unix时间戳的方法
2017/10/20 Python
Windows下安装Django框架的方法简明教程
2018/03/28 Python
[原创]Python入门教程5. 字典基本操作【定义、运算、常用函数】
2018/11/01 Python
Python爬虫获取页面所有URL链接过程详解
2020/06/04 Python
如何查看浏览器对html5的支持情况
2020/12/15 HTML / CSS
HelloFresh澳大利亚:订购你的美味食品盒、健康餐食
2018/03/28 全球购物
工作评语大全
2014/04/26 职场文书
农村门前三包责任书
2014/07/25 职场文书
医院2014国庆节活动策划方案
2014/09/21 职场文书
2015年仓库管理员工作总结
2015/04/21 职场文书
涨价通知怎么写
2015/04/23 职场文书
欧也妮葛朗台读书笔记
2015/06/30 职场文书
总结python多进程multiprocessing的相关知识
2021/06/29 Python