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__'方法的函数就是可迭代函数 ...
随机推荐
- Redis的复制是如何实现的?
前言 关系数据库通常会使用一个主服务器向多个从服务器发送更新,并使用从服务器来处理所有的读请求,Redis采用了同样方法来实现自己的复制特性. 简单总结起来就是:在接收到主服务器发送的数据初始副本之后 ...
- 【响应式编程的思维艺术】 (2)响应式Vs面向对象
目录 一. 划重点 二. 面向对象编程实例 2.1 动画的基本编程范式 2.2 参考代码 2.3 小结 三. 响应式编程实现 四. 差异对比 4.1 编程理念差异 4.2 编程体验差异 4.3 数学思 ...
- 批量修改mac系统文件的可读写权限
www 修改 /Users/feiwang 文件夹下的www 下的所有文件和文件的可读写权限.
- Java 学习笔记 IO流与File操作
可能你只想简单的使用,暂时不想了解太多的知识,那么请看这里,了解一下如何读文件,写文件 读文件示例代码 File file = new File("D:\\test\\t.txt" ...
- input框限制只能输入正整数、字母、小数、
这篇博文大部分来自于网上,为了方便自己查阅,以及帮助他人. 1,只能输入正整数 <input onkeyup="if(this.value.length==1){this.valu ...
- JS之This的用法
This的用法 This作为JavaScript中的关键字,在函数中具有四种用法. 一.直接在函数中使用,谁调用这个函数,this就指向谁 例如: var n = "指我"; fu ...
- JAVA程序员学PHP
工作之余,趁着五一假期学习下PHP,都说PHP是世界上最美的语言,而且现在应用的有这么广泛,在短期时间内在编程的市场上打得火热,好奇心趋势我去学习一下,下面便是我学习PHP记录下来的过程,和大家分享一 ...
- Selenium自动化-入门1
起初写博客是为了妹子学习,现在发现忽略了最基础的Selenium教程,所以:从本博客开始编辑 Selenium 入门知识.(学好Java) Selenium 入门 1:(学好Java) 录制回放,简单 ...
- Miller Rabin算法详解
何为Miller Rabin算法 首先看一下度娘的解释(如果你懒得读直接跳过就可以反正也没啥乱用:joy:) Miller-Rabin算法是目前主流的基于概率的素数测试算法,在构建密码安全体系中占有重 ...
- java环境配置记录
1.启动Eclipse时报错:Failed to load the JNIshared library 这种问题是因为Java与Eclipse两个软件的位数不一样,一个是32位,一个是64位,存在冲突 ...