Python程序的执⾏过程解释型语⾔和编译型语⾔
1、C++和C都是属于编译型语⾔,本来的.c⽂件都是⽤⾼级语⾔编写的,计算机是不能识别⾼级语⾔的,所以,必须要通过编译,链接等⼿段,将.c⽂件转换成可执⾏⽂件,可执⾏⽂件就是纯⼆进制⽂件,然后计算机才能够执⾏。
unix>./p:(p是可执⾏⽂件)
上述命令的过程,是外壳(shell)调⽤操作系统⼀个叫加载器的函数,它拷贝可执⾏⽂件p中的代码和数据到存储器,然后将控制转移到这个程序的开头。
2、
1. Python是⼀门解释型语⾔?
我初学Python时,听到的关于Python的第⼀句话就是,Python是⼀门解释性语⾔,我就这样⼀直相信下去,直到发现了*.pyc⽂件的存在。如果是解释型语⾔,那么⽣成的*.pyc⽂件是什么呢?c应该是compiled的缩写才对啊!
为了防⽌其他学习Python的⼈也被这句话误解,那么我们就在⽂中来澄清下这个问题,并且把⼀些基础概念给理清。
java下载过程2. 解释型语⾔和编译型语⾔
计算机是不能够识别⾼级语⾔的,所以当我们运⾏⼀个⾼级语⾔程序的时候,就需要⼀个“翻译机”来从事把⾼级语⾔转变成计算机能读懂的机器语⾔的过程。这个过程分成两类,第⼀种是编译,第⼆种是解释。
编译型语⾔在程序执⾏之前,先会通过编译器对程序执⾏⼀个编译的过程,把程序转变成机器语⾔。运⾏时就不需要翻译,⽽直接执⾏就可以了。最典型的例⼦就是C语⾔。
property management翻译解释型语⾔就没有这个编译的过程,⽽是在程序运⾏的时候,通过解释器对程序逐⾏作出解释,然后直接运⾏,最典型的例⼦是Ruby。通过以上的例⼦,我们可以来总结⼀下解释型语⾔和编译型语⾔的优缺点,因为编译型语⾔在程序运⾏之前就已经对程序做出了“翻译”,所以在运⾏时就少掉了“翻译”的过程,所以效率⽐较⾼。但是我们也不能⼀概⽽论,⼀些解释型语⾔也可以通过解释器的优化来在对程序做出翻译时对整个程序做出优化,从⽽在效率上超过编译型语⾔。
此外,随着Java等基于虚拟机的语⾔的兴起,我们⼜不能把语⾔纯粹地分成解释型和编译型这两种。
⽤Java来举例,Java⾸先是通过编译器编译成字节码⽂件(不是⼆进制码),然后在运⾏时通过解释器给解释成机器⽂件。所以我们说Java是⼀种先编译后解释的语⾔。
总结:将由⾼级语⾔编写的程序⽂件转换为可执⾏⽂件(⼆进制的)有两种⽅式,编译和解释,编译是在程序运⾏前,已经将程序全部转换成⼆进制码,⽽解释是在程序执⾏的时候,边翻译边执⾏。
3. Python到底是什么
其实Python和Java/C#⼀样,也是⼀门基于虚拟机的语⾔,我们先来从表⾯上简单地了解⼀下Python程序的运⾏过程吧。
当我们在命令⾏中输⼊python hello.py时,其实是激活了Python的“解释器”,告诉“解释器”:你要开始⼯作了。可是在“解释”之前,其实执⾏的第⼀项⼯作和Java⼀样,是编译。
熟悉Java的同学可以想⼀下我们在命令⾏中如何执⾏⼀个Java的程序:
javac hello.java(编译的过程)
java hello(解释的过程)
只是我们在⽤Eclipse之类的IDE时,将这两部给融合成了⼀部⽽已。其实Python也⼀样,当我们执⾏python hello.py时,他也⼀样执⾏了这么⼀个过程,所以我们应该这样来描述Python,Python是⼀门先编译后解释的语⾔。
4. 简述Python的运⾏过程
在说这个问题之前,我们先来说两个概念,PyCodeObject和pyc⽂件。
我们在硬盘上看到的pyc⾃然不必多说,⽽其实PyCodeObject则是Python编译器真正编译成的结果。我们先简单知道就可以了,继续向下看。
当python程序运⾏时,编译的结果则是保存在位于内存中的PyCodeObject中,当Python程序运⾏结束时,Python解释器则将PyCodeObject写回到pyc⽂件中。
当python程序第⼆次运⾏时,⾸先程序会在硬盘中寻pyc⽂件,如果到,则直接载⼊,否则就重复上⾯的过程。
所以我们应该这样来定位PyCodeObject和pyc⽂件,我们说pyc⽂件其实是PyCodeObject的⼀种持久化保存⽅式。
总结:Python也是先编译后解释的⼀门语⾔,当python程序运⾏时,编译的结果是保存在内存中的 PyCodeObject中,当Python程序运⾏结束时,Python解释器则将PyCodeObject写回到pyc⽂件中。也就是说保存,pyc⽂件是为了下次再次使⽤该脚本时避免重复编译,以此来节省时间。也就是说,只执⾏⼀次的脚本,就没必要保存其编译结果pyc,这样只是浪费空间。下⾯举例解释。
5、 运⾏⼀段Python程序
我们来写⼀段程序实际运⾏⼀下:
程序本⾝毫⽆意义。我们继续看:
然⽽我们在程序中并没有看到pyc⽂件,仍然是test.py孤零零地呆在那!(因为,test.py只是⼀次性的脚本⽂件,系统任务仅是会调⽤⼀次,所以,⽣成pyc⽂件只是浪费空间⽽已)那么我们换⼀种写法,我们把print_str⽅法换到另外的⼀个python模块中:
6. pyc的⽬的是重⽤
php文字游戏
回想本⽂的第⼆段在解释编译型语⾔和解释型语⾔的优缺点时,我说编译型语⾔的优点在于,我们可以在程序运⾏时不⽤解释,⽽直接利⽤已经“翻译”过的⽂件。也就是说,我们之所以要把py⽂件编译成pyc⽂件,最⼤的优点在于我们在运⾏程序时,不需要重新对该模块进⾏重新的解释。
所以,我们需要编译成pyc⽂件的应该是那些可以重⽤的模块,这于我们在设计软件类时是⼀样的⽬的。所以Python的解释器认为:只有import进来的模块,才是需要被重⽤的模块。
织梦漏洞分析这个时候也许有⼈会说,不对啊!你的这个问题没有被解释通啊,我的test.py不是也需要运⾏么,虽然不是⼀个模块,但是以后我每次运⾏也可以节省时间啊!
OK,我们从实际情况出发,思考下我们在什么时候才可能运⾏python xxx.py⽂件:
A. 执⾏测试时。
B. 开启⼀个Web进程时。
C. 执⾏⼀个程序脚本。
我们逐个来说,第⼀种情况我们就不⽤多说了,这个时候哪怕所有的⽂件都没有pyc⽂件都是⽆所谓的。
第⼆种情况,我们试想⼀个webpy的程序把,我们通常这样执⾏:
总结:只有模块⽂件会被认为是可能被重⽤的,所以,只⽤模型⽂件才会保存编译或者(编译+解释)后的结果.pyc⽂件。
6、 pyc的过期时间
说完了pyc⽂件,可能有⼈会想到,每次Python的解释器都把模块给持久化成了pyc⽂件,那么当我的模块发⽣了改变的时候,是不是都要⼿动地把以前的pyc⽂件remove掉呢?
当然Python的设计者是不会犯这么⽩痴的错误的。⽽这个过程其实就取决于PyCodeObject是如何写⼊pyc⽂件中的。drop table和truncate table的区别
我们来看⼀下import过程的源码吧:
这段代码⽐较长,我们只来看我标注了的代码,其实他在写⼊pyc⽂件的时候,写了⼀个Long型变量,
变量的内容则是⽂件的最近修改⽇期,同理,我们再看下载⼊pyc的代码:
不⽤仔细看代码,我们可以很清楚地看到原理,其实每次在载⼊之前都会先检查⼀下py⽂件和pyc⽂件保存的最后修改⽇期,如果不⼀致则重新⽣成⼀份pyc⽂件。
8. 写在最后的
其实了解Python程序的执⾏过程对于⼤部分程序员,包括Python程序员来说意义都是不⼤的,那么真正有意义的是,我们可以从Python 的解释器的做法上学到什么,我认为有这样的⼏点:
A. 其实Python是否保存成pyc⽂件和我们在设计缓存系统时是⼀样的,我们可以仔细想想,到底什么是值得扔在缓存⾥的,什么是不值得扔在缓存⾥的。只有要重⽤的模块才是值得编译成pyc⽂件的。
B. 在跑⼀个耗时的Python脚本时,我们如何能够稍微压榨⼀些程序的运⾏时间,就是将模块从主模块分开。(虽然往往这都不是瓶颈),那么再次运⾏时,就可以不⽤编译了,直接使⽤上次编译后的结果。
jdk运行java程序C. 在设计⼀个软件系统时,重⽤和⾮重⽤的东西是不是也应该分开来对待,这是软件设计原则的重要部分。
D. 在设计缓存系统(或者其他系统)时,我们如何来避免程序的过期,其实Python的解释器也为我们提供了⼀个特别常见⽽且有效的解决⽅案。
总结:Python是编译+解释型的语⾔,执⾏的时候是由Python解释器,逐⾏编译+解释,然后运⾏,因为在运⾏的过程中,需要编译+解释,所以Python的运⾏性能会低于编译型语⾔,⽐如C++。为了提⾼性能,Python解释器,会将模块(以后要重⽤的脚本⽂件放在模块⾥)的编译+解释的结果,保存在.pyc中。这样下次执⾏的时候,就省了编译这个环节。提⾼性能。⼀次性的脚本⽂件,解释器是不会保存编译+解释的结果,也就是没有.pyc⽂件。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论