http://python.jobbole.com/88677/?utm_source=blog.jobbole.com&utm_medium=relatedPosts

~~~~~~~~~~~~~~~~~~~~~~

划重点:

当 PyEval_EvalFrameEx 遇到 CALL_FUNCTION 字节码的时候,它会创建一个新的 Python 堆栈帧,然后用这个新的帧作为参数递归调用 PyEval_EvalFrameEx 来执行 bar

Python 的堆栈帧是分配在堆内存中的,理解这一点非常重要!Python 解释器是个普通的 C 程序,所以它的堆栈帧就是普通的堆栈。但是它操作的 Python 堆栈帧是在堆上的。除了其他惊喜之外,这意味着 Python 的堆栈帧可以在它的调用之外存活。(FIXME: 可以在它调用结束后存活)。

生成器可以在任何时候被任何函数恢复执行,因为它的堆栈帧实际上不在堆栈上——它在堆(内存)上。生成器在调用调用层次结构中的位置不是固定的,它不需要遵循常规函数执行时遵循的先进后出顺序。生成器被是被解放了的,它像云一样浮动。

1,解释器执行到 yield 后,取出栈中的最后的元素返回

2,yield 直接跳到了 fast_yield,跳过了正常函数返回的部分,也就是跳过了清理函数现场,这样下次执行的时候才能从返回的地方开始,而不是重现开始执行

PyObject *
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{
...
        case YIELD_VALUE:
            retval = POP();
            f->f_stacktop = stack_pointer;
            why = WHY_YIELD;
            goto fast_yield;
...
    assert(why != WHY_YIELD);
    /* Pop remaining stack entries. */
    while (!EMPTY()) {
        v = POP();
        Py_XDECREF(v);
    }

    if (why != WHY_RETURN)
        retval = NULL;

fast_yield:
...

    /* pop frame */
exit_eval_frame:
    Py_LeaveRecursiveCall();
    tstate->frame = f->f_back;

    return retval;
}
static PyObject *
gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
{
    PyThreadState *tstate = PyThreadState_GET();
    PyFrameObject *f = gen->gi_frame;
    PyObject *result;

    ...
        /* Push arg onto the frame's value stack */
        result = arg ? arg : Py_None;
        Py_INCREF(result);
        *(f->f_stacktop++) = result;
    }

    /* Generators always return to their most recent caller, not
     * necessarily their creator. */
    Py_XINCREF(tstate->frame);
    assert(f->f_back == NULL);
    f->f_back = tstate->frame;

    gen->gi_running = ;
    result = PyEval_EvalFrameEx(f, exc);
    gen->gi_running = ;
...
    return result;
}

可以看到 send 做的事情:

1,把传入的参数放到栈顶

2,执行 frame

3,返回执行的结果

最新文章

  1. React构建单页应用方法与实例
  2. PHP正则表达式模式修饰符详解
  3. RequireJS实例分析
  4. mongo链接报错:couldn't connect to server 127.0.0.1:27017 (127.0.0.1)
  5. SpringMvc:处理模型数据
  6. Binary Tree Level Order Traversal [LeetCode]
  7. Unity动态加载和内存管理(三合一)
  8. android 随手记 广播通知栏 二
  9. 利用js加载本地图片预览功能
  10. AlarmReceiver 与IntentService的使用
  11. MYSQL 时间计算的 3 种函数
  12. 字符集 ISO-8859-1(3)
  13. loj#6074. 「2017 山东一轮集训 Day6」子序列(矩阵乘法 dp)
  14. 「Link-Cut Tree」学习笔记
  15. CSS——nth-child()
  16. 25个SSH命令
  17. 算法(第四版)C# 习题题解——1.1
  18. Python-HTML基础
  19. C# 在网页中将Base64编码的字符串显示成图片
  20. 谈谈如何优化MYSQL数据库查询

热门文章

  1. PHP7 学习笔记(十)会话控制
  2. FastReport.Net报表故障排除方法
  3. 【原创】angularjs1.3.0源码解析之执行流程
  4. Ribbon实现Office开始菜单
  5. MySQL5.7使用错误解决:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)【取消或重设root密码】
  6. 给父元素与子元素分别设置visibility注意点
  7. break case
  8. 2017-2018-2 20155303『网络对抗技术』Exp9:Web安全基础
  9. SpringBoot集成Dubbo
  10. python 历险记(一)— python 的String,集合(List,元组,Dict)