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 相关文章推荐
Zookeeper接口kazoo实例解析
Jan 22 Python
PyCharm代码格式调整方法
May 23 Python
使用python读取csv文件快速插入数据库的实例
Jun 21 Python
python斐波那契数列的计算方法
Sep 27 Python
python http基本验证方法
Dec 26 Python
python实现彩色图转换成灰度图
Jan 15 Python
python整小时 整天时间戳获取算法示例
Feb 20 Python
十个Python练手的实战项目,学会这些Python就基本没问题了(推荐)
Apr 26 Python
python实现根据文件格式分类
Oct 31 Python
Python3的socket使用方法详解
Feb 18 Python
Python直接赋值及深浅拷贝原理详解
Sep 05 Python
Python使用xpath实现图片爬取
Sep 16 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
Laravel模型间关系设置分表的方法示例
2018/04/21 PHP
一组JS创建和操作表格的函数集合
2009/05/07 Javascript
Jquery Select操作方法集合脚本之家特别版
2010/05/17 Javascript
Document对象内容集合(比较全)
2010/09/06 Javascript
jquery调用wcf并展示出数据的方法
2011/07/07 Javascript
javascript对talbe进行动态添加、删除、验证实现代码
2012/03/29 Javascript
jQuery实现可拖动的浮动层完整代码
2013/05/27 Javascript
如何使用JS获取IE上传文件路径(IE7,8)
2013/07/08 Javascript
jquery无刷新验证邮箱地址实现实例
2014/02/19 Javascript
jQuery mobile类库使用时加载导航历史的方法简介
2015/12/04 Javascript
理解javascript模块化
2016/03/28 Javascript
javascript html5摇一摇功能的实现
2016/04/19 Javascript
JS获取鼠标相对位置的方法
2016/09/20 Javascript
Nodejs进阶:核心模块net入门学习与实例讲解
2016/11/21 NodeJs
AngularJS表格添加序号的方法
2017/03/03 Javascript
vue-cli常用设置总结
2018/02/24 Javascript
webpack配置打包后图片路径出错的解决
2018/04/26 Javascript
vue+iview 实现可编辑表格的示例代码
2018/10/31 Javascript
vue配置接口域名方法总结
2019/05/12 Javascript
轻松学习JavaScript函数中的 Rest 参数
2019/05/30 Javascript
vue调用本地摄像头实现拍照功能
2020/08/14 Javascript
Vue指令实现OutClick的示例
2020/11/16 Javascript
python中的break、continue、exit()、pass全面解析
2017/08/05 Python
python实现可逆简单的加密算法
2019/03/22 Python
Python 中PyQt5 点击主窗口弹出另一个窗口的实现方法
2019/07/04 Python
关于python中plt.hist参数的使用详解
2019/11/28 Python
解决python Jupyter不能导入外部包问题
2020/04/15 Python
Python中的None与 NULL(即空字符)的区别详解
2020/09/24 Python
Sofmap官网:日本著名的数码电器专卖店
2017/05/19 全球购物
SIMON MILLER官网:洛杉矶的生活方式品牌
2020/10/19 全球购物
大学生职业生涯规划书前言
2014/01/09 职场文书
2014国庆节幼儿园亲子活动方案
2014/09/16 职场文书
2014年涉外离婚协议书范本
2014/11/20 职场文书
城镇居民医疗保险工作总结
2015/08/10 职场文书
MySQL系列之四 SQL语法
2021/07/02 MySQL
Java Redisson多策略注解限流
2022/09/23 Java/Android