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自动化测试之连接几组测试包实例
Sep 28 Python
浅谈python多线程和队列管理shell程序
Aug 04 Python
Python序列操作之进阶篇
Dec 08 Python
python fabric实现远程部署
Jan 05 Python
Python socket网络编程TCP/IP服务器与客户端通信
Jan 05 Python
Python编程使用NLTK进行自然语言处理详解
Nov 16 Python
django文档学习之applications使用详解
Jan 29 Python
对python中数组的del,remove,pop区别详解
Nov 07 Python
Python中断多重循环的思路总结
Oct 04 Python
Numpy之reshape()使用详解
Dec 26 Python
tensorflow 变长序列存储实例
Jan 20 Python
Python中openpyxl实现vlookup函数的实例
Oct 28 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/20 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
给PHP开发者的编程指南 第一部分降低复杂程度
2016/01/18 PHP
浅谈PHP定义命令空间的几个注意点(推荐)
2016/10/29 PHP
PHP操作MongoDB实现增删改查功能【附php7操作MongoDB方法】
2018/04/24 PHP
ThinkPHP5 验证器的具体使用
2018/05/31 PHP
浅析js封装和作用域
2013/07/09 Javascript
AngularJS + Node.js + MongoDB开发的基于高德地图位置的通讯录
2015/01/02 Javascript
简述Matlab中size()函数的用法
2016/03/20 Javascript
详解JavaScript中Hash Map映射结构的实现
2016/05/21 Javascript
jquery easyUI中ajax异步校验用户名
2016/08/19 Javascript
JavaScript九九乘法口诀表的简单实现
2016/10/04 Javascript
js自定义瀑布流布局插件
2017/05/16 Javascript
微信小程序自定义toast实现方法详解【附demo源码下载】
2017/11/28 Javascript
ES10 特性的完整指南小结
2019/03/04 Javascript
用 js 写一个 js 解释器过程详解
2019/08/02 Javascript
Vue搭建后台系统需要注意的问题
2019/11/08 Javascript
ES6使用 Array.includes 处理多重条件用法实例分析
2020/03/02 Javascript
使用Vue实现一个树组件的示例
2020/11/06 Javascript
python实现从本地摄像头和网络摄像头截取图片功能
2019/07/11 Python
基于Python函数和变量名解析
2019/07/19 Python
python实例化对象的具体方法
2020/06/17 Python
Html5游戏开发之乒乓Ping Pong游戏示例(二)
2013/01/21 HTML / CSS
Html5页面点击遮罩层背景关闭遮罩层
2020/11/30 HTML / CSS
机电一体化自荐信
2013/12/10 职场文书
大学生冰淇淋店商业计划书
2014/01/14 职场文书
八年级语文教学反思
2014/02/11 职场文书
周年庆促销方案
2014/03/15 职场文书
遗嘱继承公证书
2014/04/09 职场文书
办理房产过户的委托书
2014/09/14 职场文书
省委召开党的群众路线教育实践活动总结大会报告
2014/10/21 职场文书
毕业典礼邀请函
2015/01/31 职场文书
关于React Native使用axios进行网络请求的方法
2021/08/02 Javascript
Python3.8官网文档之类的基础语法阅读
2021/09/04 Python
Python Numpy库的超详细教程
2022/04/06 Python
设置IIS Express并发数
2022/07/07 Servers