面试题

解释/编译?动态/静态?强/弱?Python 到底是一门怎样的语言?

编译 or 解释?

编译、解释都是指将(与人类亲和的)编程语言翻译成(计算机能够理解的)机器语言(Machine code)的过程。
而两者的区别就在于「翻译时机」的不同,看一个例子:

python源码编译成静态库 python 静态编译_嵌入式

Emmmmmmmmmmmmm~ 神比喻 !!

没错,编译型语言会将全部源代码一次性翻译完成,最终得到可执行文件,所以其主要特征就是「一次编译,多次执行」。编译型程序的优势在于运行效率奇高,毕竟可执行文件就是一连串可以被计算机直接执行机器指令集。而缺点在于,可移植性差(异构平台的 CPU 指令集不兼容)、大型应用的编译时间较长、而且每次修改源码都要重新编译,所以 debug 体验糟糕。典型的编译型语言有 C/C++,常见于偏底层,执行环境苛刻且追求速度的场景(e.g. 嵌入式、硬件开发、矿工);

反观解释型语言并不会直接将源码翻译成机器码,而是先翻译成中间码,再交由语言自身提供的解释器逐条解释执行,所以解释型语言的主要特征之一就是「边解释,边执行」。由此可见,解释型程序的运行效率会更低一些。而解释器存在的目的是为了提供一个与平台无关的托管运行时环境,使同一个解释型程序能够运行在不同的操作系统之上,这就是解释型型语言的另一大特征「跨平台」。

需要注意的是,Python 因为含有解释器,所以经常会被认作解释型语言。实际上这一论断并不严谨,因为 Python 程序的运行同样需要经历编译的过程。Python 自身也包含了编译器,它会将源码先编译为中间状态的字节码(Bytecode),再由解释器进行解释。如果可以的话,Python 会将这些字节码保存在临时文件 .pyc 中,以避免重复无谓的编译。当然,如果源码被修改了,则需要重新编译,直到下一次修改为止。这么做的原因无非是为了能够在支持跨平台的基础上进一步提升程序的运行效率,也正因如此使 Python 模糊了编译和解释的界限。如果单纯的将 Python 定性为解释型语言,难免会造成理解上的缺失。比如,不了解 .pyc 文件存在的意义。
所以,我更愿意将 Python 定义为一门既有编译又有解释的更高级的编程语言。

动态语言 or 静态语言?

动态、静态指的是编程语言类型系统对数据类型检查的严格程度。

静态类型语言属于严格数据类型检查,在程序编译时(compile time),就需要确定所有变量的数据类型,所以静态类型语言强制要求在使用变量之前事先声明变量的数据类型。因为类型声明机制,静态类型语言的编译器或 IDE 拥有着优秀的代码感知能力,能够更好的辅助程序员开发出复杂且庞大的应用系统程序。典型代表有 C、Java。

int anInt;
char aString[10];
anInt = 1;
aString = {"a","b","c","d","\0”};

动态类型语言则相反,属于非严格数据类型检查。程序在实际运行时(runtime),变量的数据类型才被确定。动态类型语言不需要类型声明,同一个变量可以在不同的位置被赋予各种数据类型。只有当程序执行到某条具体的赋值语句时,变量类型才会由赋值对象的数据类型决定。典型代表就是 Python。因此,Python 程序的开发具有很强的灵活性,同时开发效率也更高。不过,虽然 Python 程序员可以不关注变量的数据类型,但解释器却需要去推断变量的数据类型,这也在一定程序上影响了运行效率。而且数据类型检查不严格,会更加容易埋下不易察觉的 bug。所以,总的来说 Python 更适合于快速开发中小型应用系统。

>>> obj = 123
>>> obj = 'abc'

强类型 or 弱类型?

强、弱类型指的是编译程序时能否容忍隐式的数据类型转换。

弱类型语言能够容忍在程序运行时对变量进行隐式的数据类型转换,是一种几乎可以忽略数据类型的编程语言。可见,弱类型语言是一种类型非安全的编程语言。
例如 JavaScript:

> '1' + 2
'12'

强类型语言则相反,它是类型安全的。变量的数据类型一旦被确定,除非使用强制类型转换,否则其数据类型永远不会被改变。
例如 Python:

>>> '1' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int’ objects

那类型安全具有什么意义呢?

描述类型安全系统的最简单的方法就是描述它的对立面。有的语言(尤其是C和C++)允许做一些非常“不正当”的事情。但在合适的时候,其功能可能会很强大。但是,世界上没有免费的午餐。所谓“合适的时候”实际很少能够遇到。如使用不当,反而极有可能“搬起石头砸自己的脚”。滥用类型系统就属于这种情况。

打个比方,当程序将一个变量当作类型 A 来执行时,却意外的发现这个变量可能是类型 B,也可能什么都不是。但此时的程序可能已经通过了编译,正在运行的阶段。在这样的情形下,就很可能会导致程序崩溃或异常退出的问题。当然了,这里描述的是编程语言的类型安全系统。但很多时候即便编程语言是类型安全的,也可能被实现出类型非安全的应用程序。所以即便 Python 是类型安全的,但开发者仍需时刻谨慎的处理数据类型问题。

总的来说,强类型语言在速度上会稍逊于弱类型语言,但强类型带来的严谨性能够更好的避免许多错误。

最后

当然,我们可以简单的用「Python 是一门动态的强类型解释语言」来回答此次的问题。但我们通过对比编程语言的 编译/解释、动态/静态、强/弱类型 等特性之后应该可以得到更加深刻的理解。

Python 具有非常好的跨平台特性,同一套代码能够在不同的平台上正常的运行; Python
虽然在编译上作出了努力,但同步其他编程语言依旧会慢; Python
编程很灵活、效率很高,为此也牺牲了代码的严谨性,不适合多人协同开发大规模应用程序; Python
虽然是类型安全的编程语言,但因其太多灵活,所以很容易实现出类型非安全的应用程序;

当我们在使用一个工具时,我们首先要做的就是尝试去了解它。