《Python源码剖析》读书笔记-9 Python虚拟机中的一般表达式


第9章 Python虚拟机中的一般表达式

  • 某个指令的参数通过如下语句获取:

    1
    2
    3
    4
    5
    6
    #define HAVE_ARGUMENT	90	/* Opcodes from here have an argument: */
    #define HAS_ARG(op) ((op) >= HAVE_ARGUMENT)
    #define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])

    if (HAS_ARG(opcode))
    oparg = NEXTARG();
    • 这里,opcode大于等于90的指令都会存在一个参数,这个参数占据2个字节(2Byte),并且以小端模式存储,所以会采用这样的计算方式next_instr[-1]<<8) + next_instr[-2]
  • 对象的创建,分成以下几步:
    • 从编译得到的PyCodeObject的co_consts表中得到相关常量,或者创建一个新的PyObject(可能是Dict,List…)压入运行时栈;
    • 从编译得到的PyCodeObject的co_names表中得到相关的变量名字符串,从运行时栈中弹出第一步得到的Python对象,组成键值对,存入PyFrameObject的f_locals字典中。
  • 创建非空的Dict对象时,运行时栈中存放的是Dict的指针,DUP_TOP指令复制的也是Dict的指针,因此当LOAD_CONST,ROT_TWO,LOAD_CONST,STORE_SUBSCR这一系列指令对靠近栈顶的那个Dict插入键值对后,位于栈底的原始Dict也被改变了。
  • 从LOAD_NAMES指令对应的c代码可以看出查找变量名时是按照LGB的顺序依次进行的;但是这里没有提到如何处理闭包,也就是如何体现LEGB这样的查找顺序。我猜想应该有关闭包的Python代码编译出来的字节码和没有闭包的情形是不一样的。这个猜测有待后续验证。

欢迎关注我的微信公众号,技术·生活·思考:
后端技术小黑屋

Comments