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注释详解
Jun 01 Python
pyqt5简介及安装方法介绍
Jan 31 Python
python实现归并排序算法
Nov 22 Python
Django管理员账号和密码忘记的完美解决方法
Dec 06 Python
详解python多线程之间的同步(一)
Apr 03 Python
Python参数类型以及常见的坑详解
Jul 08 Python
python变量的存储原理详解
Jul 10 Python
flask框架路由常用定义方式总结
Jul 23 Python
基于Python新建用户并产生随机密码过程解析
Oct 08 Python
Tensorflow 模型转换 .pb convert to .lite实例
Feb 12 Python
浅谈keras中Dropout在预测过程中是否仍要起作用
Jul 09 Python
Python中os模块的简单使用及重命名操作
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.ini安全配置检测工具pcc简单介绍
2015/07/02 PHP
PHP读书笔记整理_结构语句详解
2016/07/01 PHP
浅谈php使用curl模拟多线程发送请求
2019/03/08 PHP
popdiv
2006/07/14 Javascript
浅析document.createDocumentFragment()与js效率
2013/07/08 Javascript
通过url查找a元素并点击
2014/04/09 Javascript
上传图片预览JS脚本 Input file图片预览的实现示例
2014/10/23 Javascript
JavaScript学习笔记之Cookie对象
2015/01/22 Javascript
AngularJS入门教程引导程序
2016/08/18 Javascript
JS实现获取来自百度,Google,soso,sogou关键词的方法
2016/12/21 Javascript
基于javascript实现数字英文验证码
2017/01/25 Javascript
Angular获取手机验证码实现移动端登录注册功能
2017/05/17 Javascript
ES6中javascript实现函数绑定及类的事件绑定功能详解
2017/11/08 Javascript
详解vue-cli中模拟数据的两种方法
2018/07/03 Javascript
前端防止用户重复提交js实现代码示例
2018/09/07 Javascript
vue--点击当前增加class,其他删除class的方法
2018/09/15 Javascript
elementUI 设置input的只读或禁用的方法
2018/10/30 Javascript
Vue 进阶之路(三)
2019/04/18 Javascript
python实现教务管理系统
2018/03/12 Python
python的格式化输出(format,%)实例详解
2018/06/01 Python
详解python3中tkinter知识点
2018/06/21 Python
详解Django中类视图使用装饰器的方式
2018/08/12 Python
Python shelve模块实现解析
2019/08/28 Python
pytorch AvgPool2d函数使用详解
2020/01/03 Python
python GUI库图形界面开发之PyQt5线程类QThread详细使用方法
2020/02/26 Python
css3实现一款模仿iphone样式的注册表单
2013/03/20 HTML / CSS
在HTML5中如何使用CSS建立不可选的文字
2014/10/17 HTML / CSS
HTML5 Web Workers之网站也能多线程的实现
2013/04/24 HTML / CSS
Craghoppers德国官网:户外和旅行服装
2020/02/14 全球购物
迪士尼法国在线商店:shopDisney FR
2020/12/03 全球购物
什么是URL
2015/12/13 面试题
社会调查研究计划书
2014/05/01 职场文书
电气工程及其自动化专业求职信
2014/06/23 职场文书
作文批改评语
2014/12/25 职场文书
证券公司客户经理岗位职责
2015/04/09 职场文书
Javascript中async与await的捕捉错误详解
2022/03/03 Javascript