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对小数进行除法运算的正确方法示例
Aug 25 Python
Python中使用不同编码读写txt文件详解
May 28 Python
Python简单实现子网掩码转换的方法
Apr 13 Python
python如何在终端里面显示一张图片
Aug 17 Python
Python 专题六 局部变量、全局变量global、导入模块变量
Mar 20 Python
python matplotlib画图实例代码分享
Dec 27 Python
Python 判断奇数偶数的方法
Dec 20 Python
Pandas之Dropna滤除缺失数据的实现方法
Jun 25 Python
python查看文件大小和文件夹内容的方法
Jul 08 Python
关于python中的xpath解析定位
Mar 06 Python
卸载tensorflow-cpu重装tensorflow-gpu操作
Jun 23 Python
python+flask编写一个简单的登录接口
Nov 13 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/05/26 PHP
PHP自动选择 连接本地还是远程数据库
2010/12/02 PHP
PHP实现抓取迅雷VIP账号的方法
2015/07/30 PHP
Zend Framework入门应用实例详解
2016/12/11 PHP
PHP7新功能总结
2019/04/14 PHP
Smarty模板语法详解
2019/07/20 PHP
extjs form textfield的隐藏方法
2008/12/29 Javascript
js实现checkbox全选、不选与反选的方法
2015/02/09 Javascript
jQuery实现折线图的方法
2015/02/28 Javascript
使用Browserify来实现CommonJS的浏览器加载方法
2017/05/14 Javascript
在vue项目中引入highcharts图表的方法
2019/01/21 Javascript
简单了解JavaScript异步
2019/05/23 Javascript
JS字符串与二进制的相互转化实例代码详解
2019/06/28 Javascript
vue获取验证码倒计时组件
2019/08/26 Javascript
vue-cli和v-charts实现可视化图表过程解析
2019/10/08 Javascript
JS apply用法总结和使用场景实例分析
2020/03/14 Javascript
Vue.js暴露方法给WebView的使用操作
2020/09/07 Javascript
[01:01:01]完美世界DOTA2联赛循环赛 GXR vs FTD BO2第一场 10.29
2020/10/29 DOTA
Python中用字符串调用函数或方法示例代码
2017/08/04 Python
Python使用回溯法子集树模板获取最长公共子序列(LCS)的方法
2017/09/08 Python
浅谈Series和DataFrame中的sort_index方法
2018/06/07 Python
Python连接Mssql基础教程之Python库pymssql
2018/09/16 Python
Python实现 版本号对比功能的实例代码
2019/04/18 Python
Python3.5 + sklearn利用SVM自动识别字母验证码方法示例
2019/05/10 Python
Python发展史及网络爬虫
2019/06/19 Python
Pandas实现dataframe和np.array的相互转换
2019/11/30 Python
Python3爬虫中识别图形验证码的实例讲解
2020/07/30 Python
Python实现Canny及Hough算法代码实例解析
2020/08/06 Python
Python可以用来做什么
2020/11/23 Python
德国原装品牌香水、化妆品和手表网站:BRASTY.DE
2016/10/16 全球购物
Draper James官网:知名演员瑞茜·威瑟斯彭所创品牌
2017/10/25 全球购物
烹调加工管理制度
2014/02/04 职场文书
收银员岗位职责
2014/02/07 职场文书
技术支持岗位职责
2015/02/13 职场文书
音乐课《小猫钓鱼》教学反思
2016/02/18 职场文书
Redis Stream类型的使用详解
2021/11/11 Redis