Python虚拟机中的一般表达式(二)

复杂内建对象的创建

在上一章Python虚拟机中的一般表达式(一)中,我们看到了Python是如何创建一个空的字典对象和列表对象,那么如果创建一个非空的字典对象和列表对象,Python的行为又是如何呢?demo2.py里面包含一个字典对象和列表对象,这两个对象都是在初始化时就包含元素,首先,我们看一下对应PyCodeObject中的符号表和常量表

# cat demo2.py
i = 1
s = "Python"
d = {"1": 1, "2": 2}
l = [1, 2]
# python2.5
……
>>> source = open("demo2.py").read()
>>> co = compile(source, "demo2.py", "exec")
>>> co.co_names
(‘i‘, ‘s‘, ‘d‘, ‘l‘)
>>> co.co_consts
(1, ‘Python‘, ‘1‘, 2, ‘2‘, None)

      

其次,我们再用dis模块解释一下demo2.py所对应的字节码

>>> import dis
>>> dis.dis(co)
  1           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (i)

  2           6 LOAD_CONST               1 (‘Python‘)
              9 STORE_NAME               1 (s)

  3          12 BUILD_MAP                0
             15 DUP_TOP
             16 LOAD_CONST               0 (1)
             19 ROT_TWO
             20 LOAD_CONST               2 (‘1‘)
             23 STORE_SUBSCR
             24 DUP_TOP
             25 LOAD_CONST               3 (2)
             28 ROT_TWO
             29 LOAD_CONST               4 (‘2‘)
             32 STORE_SUBSCR
             33 STORE_NAME               2 (d)

  4          36 LOAD_CONST               0 (1)
             39 LOAD_CONST               3 (2)
             42 BUILD_LIST               2
             45 STORE_NAME               3 (l)
             48 LOAD_CONST               5 (None)
             51 RETURN_VALUE

    

现在,我们来分析一下Python虚拟机是如何创建包含元素的字典对象和列表对象

首先是字典对象:

d = {"1": 1, "2": 2}
//分析结果
1	 12 BUILD_MAP                0
	 15 DUP_TOP
	 16 LOAD_CONST               0 (1)
	 19 ROT_TWO
	 20 LOAD_CONST               2 (‘1‘)
	 23 STORE_SUBSCR
	 24 DUP_TOP
	 25 LOAD_CONST               3 (2)
	 28 ROT_TWO
	 29 LOAD_CONST               4 (‘2‘)
	 32 STORE_SUBSCR
	 33 STORE_NAME               2 (d)

    

BUILD_MAP会创建一个空的字典,并压入运行时栈,这没什么可说的,我们看下BUILD_MAP之后的指令DUP_TOP

ceval.c

case DUP_TOP:
	v = TOP();
	Py_INCREF(v);
	PUSH(v);
	goto fast_next_opcode;

  

DUP_TOP会获取栈顶的元素,增加其引用,又再一次将栈顶元素压入栈中,紧接着LOAD_CONST指令又会将1这个对象压入到运行时栈,那么我们来看下前3条指令执行完毕后运行时栈和名字空间的分布:

图1-1

Python虚拟机在接下来又执行指令ROT_TWO,我们再来看一下关于这条指令所做的内容:

ceval.c

case ROT_TWO:
	v = TOP();
	w = SECOND();
	SET_TOP(w);
	SET_SECOND(v);
	goto fast_next_opcode;

  

ROT_TWO也是调用其他宏来完成任务的,我们看一下这几条宏的指令:

ceval.c

#define TOP()		(stack_pointer[-1])
#define SECOND()	(stack_pointer[-2])
#define SET_TOP(v)	(stack_pointer[-1] = (v))
#define SET_SECOND(v)	(stack_pointer[-2] = (v))

  

原来ROT_TWO这条指令会取出运行时栈的第一个元素和第二个元素,然后将其位置对调,执行完ROT_TWO之后,我们再来看一下运行时栈和名字空间的分布:

图1-2

随后又执行了一条LOAD_CONST指令,将字符串‘1‘压入到运行时栈中,之后,又执行了STORE_SUBSCR这条指令,而正是这条指令将字符串"1"和整数值1之间的映射建立在之前的字典对象上,我们来看一下STORE_SUBSCR的内容:

case STORE_SUBSCR:
	w = TOP();
	v = SECOND();
	u = THIRD();
	STACKADJ(-3);
	/* v[w] = u */
	err = PyObject_SetItem(v, w, u);
	Py_DECREF(u);
	Py_DECREF(v);
	Py_DECREF(w);
	if (err == 0) continue;
	break;

  

w是之前压入栈中的字符串"1",而v是运行时栈的自栈顶开始的第二个元素,是字典对象,而u则是最早之前压入栈中的值,即为整数值1,通过PyObject_SetItem(v, w, u)建立字符串"1"和整数值1在字典上的映射关系。同理字符串"2"和整数值2也是基于一样的字节码建立的映射关系,最后执行STORE_NAME字节码,在名字空间上建立符号d和字典对象的映射

在成功创建字典对象后并赋予初值,还会创建列表对象,列表对象会先将初值用LOAD_CONST压入运行时栈,再调用BUILD_LIST时将栈中的元素一个个压入列表对象,BUILD_LIST的内容在上一章Python虚拟机中的一般表达式(一)中已经解释,这里不再重复

l = [1, 2]
//分析结果
4	 36 LOAD_CONST               0 (1)
	 39 LOAD_CONST               3 (2)
	 42 BUILD_LIST               2
	 45 STORE_NAME               3 (l)

  

原文地址:https://www.cnblogs.com/beiluowuzheng/p/9462308.html

时间: 2024-10-14 03:31:56

Python虚拟机中的一般表达式(二)的相关文章

《python源码剖析》笔记 python虚拟机中的一般表达式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.字节码指令 LOAD_CONST:从consts表中读取序号为i的元素并压入到运行时栈中 STORE_NAME:改变local名字空间.从符号表names取序号为i的元素作为变量名, 取运行时栈的栈顶元素作为变量值,完成从变量名到变量值的映射关系的创建. BUILD_MAP:创建一个空的PyDictObject对象,并压入运行时栈 DUP_TOP:将栈顶元素的引用计数增加1,并将它再次

Python虚拟机之函数机制(二)

函数执行时的名字空间 在Python虚拟机之函数机制(一)这一章中,我们对Python中的函数调用机制有个大概的了解,在此基础上,我们再来看一些细节上的问题.在执行MAKE_FUNCTION指令时,调用了PyFunction_New方法,这个方法有一个参数是globals,这个globals最终将称为与函数f对应的PyFrameObject中的global名字空间--f_globals ceval.c case MAKE_FUNCTION: v = POP(); /* code object *

《python源码剖析》笔记 python虚拟机中的函数机制

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.Python虚拟机在执行函数调用时会动态地创建新的 PyFrameObject对象, 这些PyFrameObject对象之间会形成PyFrameObject对象链,模拟x86平台上运行时栈 2.PyFuctionObject对象 typedef struct { PyObject_HEAD PyObject *func_code: //对应函数编译后的PyCodeObject对象 Py

《python解释器源码剖析》第12章--python虚拟机中的函数机制

12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python中,PyFrameObject对象就是一个对栈帧的模拟,所以我们即将也会看到,python虚拟机在执行函数调用时会动态地创建新的PyFrameObject对象.随着函数调用链的增长,这些PyFrameObject对象之间也会形成一条PyFrameObject对象链,这条链就是对象x86平台上运行时栈

《python解释器源码剖析》第13章--python虚拟机中的类机制

13.0 序 这一章我们就来看看python中类是怎么实现的,我们知道C不是一个面向对象语言,而python却是一个面向对象的语言,那么在python的底层,是如何使用C来支持python实现面向对象的功能呢?带着这些疑问,我们下面开始剖析python中类的实现机制.另外,在python2中存在着经典类(classic class)和新式类(new style class),但是到Python3中,经典类已经消失了.并且python2官网都快不维护了,因此我们这一章只会介绍新式类. 13.1 p

Python函数中的参数(二)

当使用混合特定的参数匹配模型时,Python将会遵循以下有关顺序的法则: 1.在函数调用中,参数必须以这样的顺序出现:任何位置参数(Value).任何关键字参数(name = Value)和*sequence形式的组合,最后是**dict形式 2.在函数头部,参数必须以如下的顺序出现:任何一般参数.任何默认参数.如果有的话,是*name(在Python3.0中是*)的形式,然后是任何name或name=value keyword-only参数,最后是**name形式 Python内部是使用以下的

在windows server 2008的虚拟机中搭建openfilter(二)

openfilter安装配置 点击next出来提示点击yes 即可,应该会出来五次提示(这里是因为一共有五块硬盘,因为上一篇文章中我们加了四块硬盘,一共是五块,所以会弹出五次)都选默认就行,然后点击next会出来提示说明是否要格式化硬盘 点击yes 就OK点击edit,进行IP地址的建立输入IP地址和掩码就行做完之后会弹出一个提示因为你没有设置网关和DNS,因为不需要网关和DNS所以点击continue即可点击next即可随后需要设置密码和在输入一遍你设置的密码再次点击next进入安装界面,安心

《python源码剖析》笔记 Python虚拟机框架

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1. Python虚拟机会从编译得到的PyCodeObject对象中依次读入每一条字节码指令, 并在当前的上下文环境中执行这条字节码指令. Python虚拟机实际上是在模拟操作中执行文件的过程 PyCodeObject对象中包含了字节码指令以及程序的所有静态信息,但没有包含 程序运行时的动态信息--执行环境(PyFrameObject) 2.Python源码中的PyFrameObject

Python虚拟机框架(一)

Python虚拟机中的执行环境 Python的虚拟机实际上是在模拟操作系统运行可执行文件的过程,首先,我们先来讲一下普通的x86的机器上,可执行文件是以一种什么方式运行的. 图1-1 图1-1所展示的运行时栈的情形可以看作是如下的C代码运行时情形: #include <stdio.h> void f(int a, int b) { printf("a=%d, b=%d\n", a, b); } void g() { f(1, 2); } main(int argc, cha