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的爬虫框架Scrapy的结构与运作流程
Jan 20 Python
20招让你的Python飞起来!
Sep 27 Python
Python代码实现KNN算法
Dec 20 Python
怎么使用pipenv管理你的python项目
Mar 12 Python
python实现人脸识别经典算法(一) 特征脸法
Mar 13 Python
python实现数独游戏 java简单实现数独游戏
Mar 30 Python
详解Python的hasattr() getattr() setattr() 函数使用方法
Jul 09 Python
python调用webservice接口的实现
Jul 12 Python
python中bs4.BeautifulSoup的基本用法
Jul 27 Python
python框架flask表单实现详解
Nov 04 Python
python写一个随机点名软件的实例
Nov 28 Python
Python+redis通过限流保护高并发系统
Apr 15 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+jQuery+Ajax实现分页效果 jPaginate插件的应用
2015/10/09 PHP
PHP新建类问题分析及解决思路
2015/11/19 PHP
万能的php分页类
2017/07/06 PHP
jQuery Selector选择器小结
2010/05/06 Javascript
JavaScript 大数据相加的问题
2011/08/03 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
2013/06/08 Javascript
javascript正则表达式使用replace()替换手机号的方法
2015/01/19 Javascript
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
Bootstrap Table使用整理(四)之工具栏
2017/06/09 Javascript
关于预加载InstantClick的问题解决方法
2017/09/12 Javascript
实例教学如何写vue插件
2017/11/30 Javascript
使用Vue开发一个实时性时间转换指令
2018/01/17 Javascript
vue初尝试--项目结构(推荐)
2018/01/30 Javascript
详解Vue 多级组件透传新方法provide/inject
2018/05/09 Javascript
vue实现学生录入系统之添加删除功能
2018/07/11 Javascript
基于VUE实现的九宫格抽奖功能
2018/09/30 Javascript
[01:13]2015国际邀请赛线下观战现场
2015/08/08 DOTA
[01:02:38]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第二场 1月10日
2021/03/11 DOTA
python用10行代码实现对黄色图片的检测功能
2015/08/10 Python
Python时间的精准正则匹配方法分析
2017/08/17 Python
对Python2与Python3中__bool__方法的差异详解
2018/11/01 Python
Python多线程threading模块用法实例分析
2019/05/22 Python
Python 实用技巧之利用Shell通配符做字符串匹配
2019/08/23 Python
flask框架自定义url转换器操作详解
2020/01/25 Python
python异常处理、自定义异常、断言原理与用法分析
2020/03/23 Python
浅谈css3中的前缀
2016/07/20 HTML / CSS
泰国第一的化妆品网站:Konvy
2018/02/25 全球购物
大学新生军训方案
2014/05/03 职场文书
给女朋友道歉的话大全
2015/01/20 职场文书
2016年社区服务活动总结
2016/04/06 职场文书
在CSS中映射鼠标位置并实现通过鼠标移动控制页面元素效果(实例代码)
2021/04/22 HTML / CSS
Python趣味实战之手把手教你实现举牌小人生成器
2021/06/07 Python
Java基于字符界面的简易收银台
2021/06/26 Java/Android
JavaWeb Servlet实现网页登录功能
2021/07/04 Java/Android
海贼王十大潜力果实,路飞仅排第十,第一可毁世界(震震果实)
2022/03/18 日漫
html中两种获取标签内的值的方法
2022/06/10 HTML / CSS