python解释型语言的说明

为什么称python为解释型语言?

为什么python相比C执行会慢?

什么是解释型语言?

Python 是怎么实现动态类型的呢?

从小白的角度来解释这些问题。

首先,大部分语言为编译型或解释型,如C/C++等为编译型,python为解释型语言,下面主要对比这两种方式来阐述python解释型言语执行过程。

先抛出其中一个结论:C和Python去游泳,C已经换好泳衣准备下水了,而Python才刚开始换衣服,Python能快吗?

先简单了解C从源代码到机器执行的过程:

C源文件通过预处理、编译、汇编、链接,最终机器执行目标代码(二进制)

预处理:主要处理以下指令:宏定义指令,条件编译指令,头文件包含指令。 预处理所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令,头文件都被展开(递归展开)的文件

    编译:将源代码转为汇编代码(机器不会识别汇编代码);

    汇编:生成的汇编代码翻译成符合一定格式的机器代码(二进制);

    链接:简单理解为两个作用,一是修改目标文件中的信息,对地址做重定位,二是把多个目标文件合并成一个可执行文件;

    执行:机器识别二进制(这个都知道吧..),机器直接跑二进制;


1、接下来就是python执行过程:

    编译:将源文件转为字节码。编译结果也就是 PyCodeObject 对象,只会存在于内存中,而某个模块的 Python 代码执行完后,就会将编译结果保存到了 pyc 文件中,这样下次就不用编译,直接加载到内存中。pyc 文件只是 PyCodeObject 对象在硬盘上的表现形式;
一个 pyc 文件包含了三部分信息:Python 的 magic number、pyc 文件创建的时间信息,以及 PyCodeObject 对象

    执行:Python虚拟机用解释的方式执行代码;

2、如何理解解释型语言:

解释器不产生目标机器代码,而是产生中间代码,硬件看不懂中间代码;

解释型代码是将源代码逐一解释成可执行的机器指令,因为效率低下;

上面其实大概了解了一下,再细一点。

.pyc的作用?

    一个 pyc 文件包含了三部分信息:Python 的 magic number、pyc 文件创建的时间信息,以及 PyCodeObject 对象。

magic number 是 Python 定义的一个整数值。一般来说,不同版本的 Python 实现都会定义不同的 magic number,这个值是用来保证 Python 兼容性的。比如要限制由低版本编译的 pyc 文件不能让高版本的 Python 程序来执行,只需要检查 magic number 不同就可以了。由于不同版本的 Python 定义的字节码指令可能会不同,如果不做检查,执行的时候就可能出错

Python 是怎么实现动态类型的呢?

    答案就藏在具体存储的对象上。变量 a 仅仅只是一个符号(实际上是一个字符串对象),类型信息是存储在对象上的。在 Python 中,对象机制的核心是类型信息和引用计数(引用计数属于垃圾回收的部分)。

因为 a 和 b 并不存储类型信息,因此当执行 a + b 的时候就必须先检查类型,比如 1 + 2 和 “1” + “2” 的结果是不一样的。

字节码该怎么理解?

    Python 标准库提供了用来生成代码对应字节码的工具 dis。dis 提供一个名为 dis 的方法,这个方法接收一个 code 对象,然后会输出 code 对象里的字节码指令信息。


import模块会如何执行?

import 指令是用来载入 module 的,如果需要,也会顺道做编译的事。但 import 指令,还会做一件重要的事情就是把 import 的那个 module 的代码执行一遍,这件事情很重要。Python 是解释执行的,连函数都是执行的时候才创建的。如果不把那个 module 的代码执行一遍,那么 module 里面的函数都没法创建,更别提去调用这些函数了。
执行代码的另外一个重要作用,就是在这个 module 的命名空间中,创建模块内定义的函数和各种对象的符号名称(也就是变量名),并将其绑定到对象上,这样其他 module 才能通过变量名来引用这些对象。
Python 虚拟机还会将已经 import 过的 module 缓存起来,放到一个全局 module 集合 sys.modules 中。这样做有一个好处,即如果程序的在另一个地方再次 import 这个模块,Python 虚拟机只需要将全局 module 集合中缓存的那个 module 对象返回即可。

你现在一定想到了 sys.modules 是一个 dict 对象,可以通过 type(sys.modules) 来验证

理解Python的多线程

在提到多线程的时候,往往要关注线程如何同步,如何访问共享资源。Python 是通过一个全局解释器锁 GIL(Global Interpreter Lock)来实现线程同步的。当 Python 程序只有单线程时,并不会启用 GIL,而当用户创建了一个 thread 时,表示要使用多线程,Python 解释器就会自动激活 GIL,并创建所需要的上下文环境和数据结构。
Python 字节码解释器的工作原理是按照指令的顺序一条一条地顺序执行,Python 内部维护着一个数值,这个数值就是 Python 内部的时钟,如果这个数值为 N,则意味着 Python 在执行了 N 条指令以后应该立即启动线程调度机制,可以通过下面的代码获取这个数值。

1 import sys
2 sys.getcheckinterval() # 100

线程调度机制将会为线程分配 GIL,获取到 GIL 的线程就能开始执行,而其他线程则必须等待。由于 GIL 的存在,Python 的多线程性能十分低下,无法发挥多核 CPU 的优势,性能甚至不如单线程。因此如果你想用到多核 CPU,一个建议是使用多进程。

了解垃圾回收
在讲到垃圾回收的时候,通常会使用引用计数的模型(可以百度了解一下),这是一种最直观,最简单的垃圾收集技术。Python 同样也使用了引用计数,但是引用计数存在这些缺点:
• 频繁更新引用计数会降低运行效率
• 引用计数无法解决循环引用问题

Python 在引用计数机制的基础上,使用了主流垃圾收集技术中的标记——清除和分代收集两种技术。


结语:

后面大部分是照抄网上的一些资料,如有不妥之处,请及时告知,一定修改。

参考资料其中部分:

https://www.restran.net/2015/10/22/how-python-code-run/

https://www.zhihu.com/question/21539353

http://www.cnblogs.com/kym/archive/2012/05/14/2498728.html






  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值