转自:http://blog.csdn.net/helloxiaozhe/article/details/78104975
(1)python执行原理
这里的解释执行是相对于编译执行而言的。我们都知道,使用C/C++之类的编译性语言编写的程序,是需要从源文件转换成计算机使用的机器语言,经过链接器链接之后形成了二进制的可执行文件。运行该程序的时候,就可以把二进制程序从硬盘载入到内存中并运行。
但是对于Python而言,python源码不需要编译成二进制代码,它可以直接从源代码运行程序。当我们运行python文件程序的时候,python解释器将源代码转换为字节码,然后再由python解释器来执行这些字节码。这样,python就不用担心程序的编译,库的链接加载等问题了。
对于python解释语言,有以下3方面的特性:
在具体计算机上实现一种语言,首先要确定的是表示该语言语义解释的虚拟计算机,一个关键的问题是程序执行时的基本表示是实际计算机上的机器语言还是虚拟机的机器语言。这个问题决定了语言的实现。根据这个问题的回答,可以将程序设计语言划分为两大类:编译型语言和解释型语言。
当我们执行Python代码的时候,在Python解释器用四个过程“拆解”我们的代码,最终被CPU执行返回给用户。
首先当用户键入代码交给Python处理的时候会先进行词法分析,例如用户键入关键字或者当输入关键字有误时,都会被词法分析所触发,不正确的代码将不会被执行。
下一步Python会进行语法分析,例如当"for i in test:"中,test后面的冒号如果被写为其他符号,代码依旧不会被执行。
下面进入最关键的过程,在执行Python前,Python会生成.pyc文件,这个文件就是字节码,如果我们不小心修改了字节码,Python下次重新编译该程序时会和其上次生成的字节码文件进行比较,如果不匹配则会将被修改过的字节码文件进行覆盖,以确保每次编译后字节码的准确性。
那么什么是字节码?字节码在Python虚拟机程序里对应的是PyCodeObject对象。.pyc文件是字节码在磁盘上的表现形式。简单来说就是在编译代码的过程中,首先会将代码中的函数、类等对象分类处理,然后生成字节码文件。有了字节码文件,CPU可以直接识别字节码文件进行处理,接着Python就可执行了。
Python中有一个内置函数compile(),可以将源文件编译成codeobject,首先看这个函数的说明:
compile(...) compile(source, filename, mode[, flags[, dont_inherit]]) -> code object
参数1:源文件的内容字符串
参数2:源文件名称
参数3:exec-编译module,single-编译一个声明,eval-编译一个表达式 一般使用前三个参数就够了
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#src_file.py
#some function
def
f(d
=
0
):
c
=
1
print
"hello"
a
=
9
b
=
8
f()
>>> a
=
open
(
'src_file.py'
,
'r'
).read()
#命令行模式中打开源文件进行编译
>>> co
=
compile
(a,
'src_file'
,
'exec'
)
>>>
type
(co)
<
type
'code'
>
#编译出了codeobject对象
|
codeobject有哪些变量,接上节的内容分析一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
>>>
print
co.co_names
#所有的符号名称
(
'f'
,
'a'
,
'b'
)
>>>
print
co.co_name
#模块名、函数名、类名
>>>
print
co.co_consts
#常量集合、函数f和两个int常量a,b,d
(
0
, >>>
print
co.co_consts[
1
].co_varnames
#可以看到f函数也是一个codeobject,打印f中的局部变量
(
'c'
,)
>>>
print
co.co_code
#字节码指令
dZdZdZedS
>>>
print
co.co_consts[
1
].co_firstlineno
#代码块在文件中的起始行号
2
>>>
print
co.co_stacksize
#代码栈大小
2
>>>
print
co.co_filename
#文件名
src_file
#模块名、函数名、类名
|
codeobject的co_code代表了字节码,这个字节码有什么含义?我们可以使用dis模块进行python的反编译:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import
dis
dis.dis(co)
>>> output
2
0
LOAD_CONST
0
(
0
)
3
LOAD_CONST
1
(
6
MAKE_FUNCTION
1
9
STORE_NAME
0
(f)
5
12
LOAD_CONST
2
(
9
)
15
STORE_NAME
1
(a)
6
18
LOAD_CONST
3
(
8
)
21
STORE_NAME
2
(b)
7
24
LOAD_NAME
0
(f)
27
CALL_FUNCTION
0
30
POP_TOP
31
LOAD_CONST
4
(
None
)
34
RETURN_VALUE
|
从反编译的结果来看,python字节码其实是模仿的x86的汇编,将代码编译成一条一条的指令交给一个虚拟的cpu去执行。