python生成器原理剖析

函数的调用满足“后进先出”的原则,也就是说,最后被调用的函数应该第一个返回,函数的递归调用就是一个经典的例子。显然,内存中以“后进先出”方式处理数据的栈段是最适合用于实现函数调用的载体,在编译型程序语言中,函数被调用后,函数的参数,返回地址,寄存器值等数据会被压入栈,待函数体执行完毕,将上述数据弹出栈。这也意味着,一个被调用的函数一旦执行完毕,它的生命周期就结束了。

在python这样的解释型语言中,函数的调用也是依赖栈的。之前说过,python的标准解释器是用C写的。解释器用一个叫做PyEval_EvalFrameEx的C函数来执行python程序。对于一个python中的函数,解释器接受一个python的栈帧对象,并在这个栈帧的上下文中执行python字节码。

我们来看看这样一个例子:

import dis

def foo():
bar() def bar():
pass print(dis.dis(foo))

我们用dis模块可以查看python程序的字节码,下面是函数foo()的字节码:

0 LOAD_GLOBAL              0 (bar)
2 CALL_FUNCTION 0
4 POP_TOP
6 LOAD_CONST 0 (None)
8 RETURN_VALUE

foo函数将bar加载到栈中并调用它,然后从栈中弹出返回值,最后加载并返回None,当PyEval_EvalFrameEx遇到CALL_FUNCTION字节码的时候,它会创建一个新的python栈帧,然后用这个新的帧作为参数递归调用PyEval_EvalFrameEx来执行bar。不过有一点要注意的是,python解释器是个普通的C程序,所以它的堆栈帧就是普通的堆栈。但是它操作的python堆栈帧是分配在堆上的,所以python的栈帧可以在它的调用之外存活。而且可以显式的保存下来。

这是python生成器的技术基础,下面是一个生成器:

def gen():
yield 1
yield 2 g = gen()
next(g) print(type(g))

返回的结果是:

<class 'generator'>

调用gen()产生的所有生成器都指向同一个代码对象,但是每个都有自己的堆栈帧。这个堆栈帧并不存在于实际的堆栈上,它在堆内存上等待着被使用。

堆栈帧有个“last instruction”指针,指向最近执行的那条指令。刚开始的时候last instruction指针是-1意味着生成器尚未开始,这就是为什么上面的例子中有next(g)这行代码。生成器可以在任何时候被任何函数恢复执行,因为它的栈帧实际上不在栈上而是在堆上。生成器在调用调用层次结构中的位置不是固定的,也不需要遵循常规函数执行时遵循的先进后出顺序。因为这些特性,生成器不仅能用于生成可迭代对象,还可以用于实现多任务协作。

python生成器原理剖析的更多相关文章

  1. Python字符串原理剖析------万恶的+号

    字符串原理剖析pyc文件,执行python代码时,如果导入了其他的.py文件,那么执行过程中会自动生成一个与其同名的.pyc文件,该文件就是python解释器变异之后产生的字节码 PS:代码经过编译可 ...

  2. 分布式全局ID生成器原理剖析及非常齐全开源方案应用示例

    为何需要分布式ID生成器 **本人博客网站 **IT小神 www.itxiaoshen.com **拿我们系统常用Mysql数据库来说,在之前的单体架构基本是单库结构,每个业务表的ID一般从1增,通过 ...

  3. 【python之路29】python生成器generator与迭代器

    一.python生成器 python生成器原理: 只要函数中存在yield,则函数就变为生成器函数 #!usr/bin/env python # -*- coding:utf-8 -*- def xr ...

  4. 推荐《深入浅出深度学习原理剖析与python实践》PDF+代码

    <深入浅出深度学习原理剖析与Python实践>介绍了深度学习相关的原理与应用,全书共分为三大部分,第一部分主要回顾了深度学习的发展历史,以及Theano的使用:第二部分详细讲解了与深度学习 ...

  5. 深入浅出深度学习:原理剖析与python实践_黄安埠(著) pdf

    深入浅出深度学习:原理剖析与python实践 目录: 第1 部分 概要 1 1 绪论 2 1.1 人工智能.机器学习与深度学习的关系 3 1.1.1 人工智能——机器推理 4 1.1.2 机器学习—— ...

  6. python——生成器

    python——生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个 ...

  7. MapReduce/Hbase进阶提升(原理剖析、实战演练)

    什么是MapReduce? MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归约)",和他们 ...

  8. 开源 serverless 产品原理剖析 - Kubeless

    背景 Serverless 架构的出现让开发者不用过多地考虑传统的服务器采购.硬件运维.网络拓扑.资源扩容等问题,可以将更多的精力放在业务的拓展和创新上. 随着 serverless 概念的深入人心, ...

  9. ARouter原理剖析及手动实现

    ARouter原理剖析及手动实现 前言 路由跳转在项目中用了一段时间了,最近对Android中的ARouter路由原理也是研究了一番,于是就给大家分享一下自己的心得体会,并教大家如何实现一款简易的路由 ...

随机推荐

  1. postman切换环境

    原文链接:https://www.cnblogs.com/nicole-zhang/p/11498384.html 通常会有多个测试环境,针对同一个接口来说,可能只是域名有变化,此时可以添加postm ...

  2. Arduino连接LCD1602显示屏

    简介 LCD1602是一种工业字符型液晶,能够同时显示16x02即32个字符.LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,即可以显示出图形.[百度百科] 引脚说明 ...

  3. Pytorch中的自动求梯度机制和Variable类

    自动求导机制是每一个深度学习框架中重要的性质,免去了手动计算导数,下面用代码介绍并举例说明Pytorch的自动求导机制. 首先介绍Variable,Variable是对Tensor的一个封装,操作和T ...

  4. 【JMeter_19】JMeter逻辑控制器__简单控制器<Simple Controller>

    简单控制器<Simple Controller> 业务逻辑: 就像他的名字一样,简单,可以理解为一个文件夹,就是分组用的,没有其他特殊功能,但相比不添加简单控制器,区别在于简单控制器可以被 ...

  5. 使用vuex中的store存储数据

    Vuex是一个专门为Vue.js应用程序开发的状态管理模式,这个状态自管理应用包括三个模式 state 驱动应用的数据源 view 以声明方式将state映射到视图 actions 响应在view上的 ...

  6. 如何修改git commit的author信息

    本地有多个git账号时,容易发生忘记设置项目默认账号,最后以全局账号提交的情况,其实对代码本身并无影响,只是提交记录里显示的是别的名字稍显别扭. 举个例子:  查看提交日志,假设以a(a@email. ...

  7. skywalking7 源码解析 (3) :agent启动服务分析以及性能影响

    skywalking必看的文章,转载自https://blog.csdn.net/u010928589/article/details/106608864/

  8. JavaWeb网上图书商城完整项目--day02-6.ajax校验功能之页面实现

    1 .现在我们要在regist.js中实现ajax的功能,使用用户名到后台查询是否注册,邮箱是否到后台注册,验证码是否正确的功能 我们来看regist.js的代码 //该函数在html文档加载完成之后 ...

  9. React实战教程之从零开始手把手教你使用 React 最新特性Hooks API 打造一款计算机知识测验App

    项目演示地址 项目演示地址 项目代码结构 前言 React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐.React Hoo ...

  10. Riccati方程迭代法求解

    根据上述迭代法求解P,P为Riccati方程的解,然而用LQR需要计算K,再将K算出. (迭代过程中 ,我们可以将此算法和dlqr函数求解的参数进行对比,当误差小于我们设置的允许误差我们就可以把此算法 ...