python生成器源码戏说

Python生成器源码剖析

生成器是个什么鬼?

生成器(Generator)在python2.3时成为python的标准特性,因此也多加了一个yield的关键字.(是的,就是java线程让步的那个yield).生成器最神奇的特性就是: 一个函数可以返回多次结果,而不是像普通函数一样只返回一次.(神不神奇,惊不惊喜~)

普通的python函数内部, 加个yield关键字, python解析器就将该函数视为一个生成器函数. 但是生成器函数不是生成器本身,而是生成器工厂.所以调用一个生成器函数时, 将创建一个生成器对象. 当外部需要从这个生成器获取值时,生成器会通过yield返回值,而非普通函数的return方法.这个过程中, yield偷偷做了两件事:

  • 将值返回给调用方
  • 标记当前执行位置, 当生成器再运行时,从标记位置恢复运行

说了这么多,可以上代码了

def return_a_generator():  # 这货是个生成器函数
    yield 'foobar'
    yield 42
    yield 'hello'
复制代码
generator = return_a_generator()   #这步操作只是为了产生生成器对象, 也可以称为激活
复制代码
next(generator) # 真二八经的第一次调用,next就是一个调用方
复制代码
'foobar'
复制代码
next(generator) # 我还可以被调用哦
复制代码
42
复制代码
next(generator) # 这么优秀的我还是可以被调用
复制代码
'hello'
复制代码
next(generator)  # 好吧玩脱了
复制代码
---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-18-8b45440e27eb> in <module>
----> 1 next(generator)  # 好吧玩脱了


StopIteration: 
复制代码

哦了,生成器就简单介绍到这里, 下面开始正式剖析,这神奇特性的实现原理.

Python运行时核心对象

python世界里,所有东西都是对象,不仅我们看的到基本类型(int, str, list等实例),类本身也是对象哦!但这都不算啥,真正令人叫绝的是,python各种运行时核心组件(代码块, 函数,帧)也都是对象. 下面就依次介绍涉及生成器流程的各个核心对象。(为了使文章不至于太枯燥,将穿插一段狗血虐心的言情剧,大致剧情是女神(一段生成器代码)如何在一个个备胎的助攻下,最终跟渣男(cpu)走在了一起)

PyCodeObject(1号备胎)

当python代码(py文件)被python虚拟机编译后(即将python源码转为python字节码),会将编译结果保存到pyc文件中,pyc文件里 保存的格式就是PyCodeObject的序列化格式.因此他是女神的第一个备胎.PyCodeObject 真容如下:

typedef struct {
    PyObject_HEAD
    int co_argcount;		/* #arguments, except *args */
    int co_nlocals;		/* #local variables */
    int co_stacksize;		/* #entries needed for evaluation stack */
    int co_flags;		/* CO_..., see below */
    PyObject *co_code;		/* instruction opcodes python字节码,女神本尊*/
    PyObject *co_consts;	/* list (constants used) */
    PyObject *co_names;		/* list of strings (names used) */
    PyObject *co_varnames;	/* tuple of strings (local variable names) */
    PyObject *co_freevars;	/* tuple of strings (free variable names) */
    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
    /* The rest doesn't count for hash/cmp */
    PyObject *co_filename;	/* string (where it was loaded from) 认识女神的地方*/
    PyObject *co_name;		/* string (name, for reference) 女神的名字*/
    int co_firstlineno;		/* first source line number */
    PyObject *co_lnotab;	/* string (encoding addr<->lineno mapping) See
				   Objects/lnotab_notes.txt for details. */
    void *co_zombieframe;     /* for optimization only (see frameobject.c) */
    PyObject *co_weakreflist;   /* to support w
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值