Python是如何实现生成器的原理
python中函数调用的实质原理:
python解释器(即python.exe)其实是用C语言编写的, 在执行python代码时,实际上是在用一个叫做Pyeval_EvalFramEx(C语言的函数)去执行代码中的函数,(实际上python中的程序实际上是运行在C语言之上的),运行此函数的时候,首先会在内存的堆区创建一个栈帧(stack frame),python中一切皆对象,在栈帧中间将要执行的代码编译成为字节码对象。 然后在栈帧的上下文中去运行字节码,可以用dis.dis()函数查看函数的字节码。
import dis
def foo():
bar()
def bar():
pass
print(dis.dis(foo)) 结果:
20 0 LOAD_GLOBAL 0 (bar)
2 CALL_FUNCTION 0
4 POP_TOP
6 LOAD_CONST 0 (None)
8 RETURN_VALUE
None
字节码解释:当foo调用子函数bar时候,又会创建一个栈帧,然后将函数的控制权交给新的栈帧,然后去运行bar的字节码,然后就有了两个栈帧了。因为所有的栈帧都是分配在堆的内存上,(函数调用完毕不会被立即回收)这就决定了栈帧可以独立于调用者存在,(即foo即使不存在了退出了也没有关系,只要有指针指向bar的栈帧,就可以对其进行控制)具体看一下代码:foo()调用完毕了之后,由于全局变量指向了bar中的栈帧对象,所以print(frame.f_code.co_name)语句输出产生当前栈帧对象的对象名,即bar,然后caller_frame = frame.f_back语句将调用者(foo)的栈帧对象获取到,然后打印出来,即foo。
import inspect
import dis frame = None
def foo():
bar()
def bar():
global frame
frame = inspect.currentframe()
foo()
print(frame.f_code.co_name)
caller_frame = frame.f_back
print(caller_frame) 输出结果:
bar
foo
图解如下:heap(堆区), recurse(递归,图中意思即foo递归调用了bar)
堆区的PyFrameObject表示生成的栈帧对象,f_code表示执行函数的字节码,f_back表示调用者函数的字节码。

生成器的实现原理:
def gen_fun():
yield 'a'
name = 'bobby1'
yield 'b'
age = 30
return 'frank'
import dis
gen = gen_fun()
print(dis.dis(gen)) #打印gen函数的字节码
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals) 输出结果:
20 0 LOAD_CONST 1 ('a')
2 YIELD_VALUE
4 POP_TOP 21 6 LOAD_CONST 2 ('bobby1')
8 STORE_FAST 0 (name) 22 10 LOAD_CONST 3 ('b')
12 YIELD_VALUE
14 POP_TOP 23 16 LOAD_CONST 4 (30)
18 STORE_FAST 1 (age) 24 20 LOAD_CONST 5 ('frank')
22 RETURN_VALUE
None
-1
{}
2
{}
12
{'name': 'bobby1'}
真是因为有yield实现生成器函数,使得我们可以自由控制函数的运行于暂停,这个是协程实现的基础。
生成器的应用实例:用生成器函数读取一行的超大文件。
def yield_str(file, spilt):
buf = ''
while True: while spilt in buf:
pos = buf.index(spilt)
yield buf[:pos]
buf = buf[pos + len(spilt):]
chunk = file.read(100)
if not chunk:
yield buf
break
buf += chunk with open('txt.txt', encoding='utf-8') as file:
for i in yield_str(file, ','):
print(i)
Python是如何实现生成器的原理的更多相关文章
- Python 中生成器的原理
生成器的使用 在 Python 中,如果一个函数定义的内部使用了 yield 关键字,那么在执行函数的时候返回的是一个生成器,而不是常规函数的返回值. 我们先来看一个常规函数的定义,下面的函数 f() ...
- Python下探究随机数的产生原理和算法
资源下载 #本文PDF版下载 Python下探究随机数的产生原理和算法(或者单击我博客园右上角的github小标,找到lab102的W7目录下即可) #本文代码下载 几种随机数算法集合(和下文出现过的 ...
- Python学习之旅—生成器对象的send方法详解
前言 在上一篇博客中,笔者带大家一起探讨了生成器与迭代器的本质原理和使用,本次博客将重点聚焦于生成器对象的send方法. 一.send方法详解 我们知道生成器对象本质上是一个迭代器.但是它比迭代器对 ...
- Python源代码剖析笔记3-Python运行原理初探
Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...
- 小白的Python之路 day4 生成器并行运算
一.概述 我们已经明白生成器内部的结构,其实就是通过像函数这样的东西实现的! 多线程和单线程:简单来说多线程就是并行运算,单线程就是串行运算 二.生成器执行原理 第一步:生成一个生成器 第二步:执行 ...
- python基础—迭代器、生成器
python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...
- Python之迭代器,生成器
迭代器 1.什么是可迭代对象 字符串.列表.元组.字典.集合都可以被for循环,说明他们都是可迭代的. from collections import Iterable l = [1,2,3,4] t ...
- python之迭代器与生成器
python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...
- day13 python学习 迭代器,生成器
1.可迭代:当我们打印 print(dir([1,2])) 在出现的结果中可以看到包含 '__iter__', 这个方法,#次协议叫做可迭代协议 包含'__iter__'方法的函数就是可迭代函数 ...
随机推荐
- #5 Python面向对象(四)
前言 本节将是Python面向对象的最后一篇博文了,这节将记录类的特殊方法.特殊成员方法.旧类和新类的不同,以及一些其他知识.Go! 一.类的特殊方法 Python有三种特殊方法:实例方法.静态方法. ...
- jQuery中关于全选、全不选和反选
1.首先我们要获取当前点击的对象,然后得到点击事件, 判断他的状态如果是checked的话就把该第二行的选中, 否则就取消选中. 2.当第二列功能小项没有全部选中时,该行第一列的复选款也要取消 ...
- SpringMVC进行文件上传
进行文件上传前需要添加相应的依赖 在xml文件中进行相应的文件上传解析器的配置 注意:这里有个坑,因为没注意,再排查错误的时候花了一点时间.就是给bean的id一定要是. 否者就会报如下的错误:
- 20190321-HTML基本结构
目录 1.HTML概念 超文本标记语言 2.HTML版本 HTML HTML5 3.HTML基本结构 基本结构 元素.标签.属性 4.HTML常用标签 内容 1.HTML概念 HTML(HyperTe ...
- [python爬虫]Requests-BeautifulSoup-Re库方案--robots协议与Requests库实战
[根据北京理工大学嵩天老师“Python网络爬虫与信息提取”慕课课程编写 慕课链接:https://www.icourse163.org/learn/BIT-1001870001?tid=100223 ...
- linux命令df中df -h和df -i
df 命令: linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 1.命令格式: df [选项] [ ...
- windows10 企业版完整激活
windows10 企业版完整激活 cmd管理员运行 1. 以管理员身份执行cmd命令,然后输入以下命令: slmgr.vbs /upk 由于Win10正式版允许在命令提示符界面使用"Ct ...
- Android获取定位权限,获取设备所在的经纬度
转载请标明出处:http://www.cnblogs.com/tangZH/p/8969898.html 前言: 有时候我们仅仅是想要获取设备所在的经纬度,那么直接调用Android相关的api就可 ...
- AndroidTV端的requestFocus()问题
每次开机盒子或者电视的时候,发现给某些控件设置请求焦点 requestFocus 会失效 最终的解决办法就是延时请求 view.postDelayed(new Runnable() { @Overri ...
- QT信号槽connect的第五个参数
用过QT的小伙伴都知道连接信号槽的connect方法,但是这个方法有第五个参数,一般都是用的默认的 connect(th,SIGNAL(started()),tmpmyobject,SLOT(show ...