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 相关文章推荐
wxPython框架类和面板类的使用实例
Sep 28 Python
Python EOL while scanning string literal问题解决方法
Sep 18 Python
python计算一个序列的平均值的方法
Jul 11 Python
解决pycharm界面不能显示中文的问题
May 23 Python
Tornado Web Server框架编写简易Python服务器
Jul 28 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
Nov 07 Python
python数据类型之间怎么转换技巧分享
Aug 20 Python
python读取文件指定行内容实例讲解
Mar 02 Python
Anaconda和ipython环境适配的实现
Apr 22 Python
pandas统计重复值次数的方法实现
Feb 20 Python
pycharm代码删除恢复的方法
Jun 26 Python
Python 中的Sympy详细使用
Aug 07 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代码
2010/08/08 PHP
php判断数组元素中是否存在某个字符串的方法
2014/06/14 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
2014/06/26 PHP
PHP设计模式之工厂模式定义与用法详解
2018/04/03 PHP
javascript 放大镜效果js组件 qsoft.PopBigImage.v0.35 加入了chrome支持
2009/04/07 Javascript
再谈ie和firefox下的document.all属性
2009/10/21 Javascript
JavaScript经典效果集锦
2010/07/06 Javascript
基于jquery扩展漂亮的下拉框可以二次修改
2013/11/19 Javascript
input链接页面、打开新网页等等的具体实现
2013/12/30 Javascript
移除AngularJS下URL中的#字符的方法
2015/06/19 Javascript
js实现表单多按钮提交action的处理方法
2015/10/24 Javascript
javascript实现label标签跳出循环操作
2016/03/06 Javascript
AngularJS实用开发技巧(推荐)
2016/07/13 Javascript
前端设计师们最常用的JS代码汇总
2016/09/25 Javascript
Bootstrap CDN和本地化环境搭建
2016/10/26 Javascript
vue省市区三联动下拉选择组件的实现
2017/04/28 Javascript
Angular2+如何去除url中的#号详解
2017/12/20 Javascript
微信小程序实现slideUp、slideDown滑动效果及点击空白隐藏功能示例
2018/12/11 Javascript
Vue父组件如何获取子组件中的变量
2019/07/24 Javascript
node.js制作一个简单的登录拦截器
2020/02/10 Javascript
vue使用better-scroll实现滑动以及左右联动
2020/06/30 Javascript
Js图片点击切换轮播实现代码
2020/07/27 Javascript
JavaScript实现点击出现子菜单效果
2021/02/08 Javascript
用Python解析XML的几种常见方法的介绍
2015/04/09 Python
浅谈Python中range和xrange的区别
2017/12/20 Python
对Python中的@classmethod用法详解
2018/04/21 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
2014乡镇党政班子四风问题思想汇报
2014/09/14 职场文书
2014小学语文教师个人工作总结
2014/12/03 职场文书
交通事故死亡赔偿协议书
2014/12/03 职场文书
初中作文评语集锦
2014/12/25 职场文书
语文复习计划
2015/01/19 职场文书
仓管员岗位职责
2015/02/03 职场文书
贴吧吧主申请感言
2015/08/03 职场文书
Python如何利用正则表达式爬取网页信息及图片
2021/04/17 Python
MySQL完整性约束的定义与实例教程
2021/05/30 MySQL