Python解释器简介(4):动态语言
admin
2023-07-31 00:48:26
0

这是Python解释器简介的第四部分。阅读第一部分、第二部分和第三部分。如果你喜欢这个系列的话,那就把它分享到Hacker School吧。我是那里的管理员。

当我开始研究python内部工作的时候,我一直很困惑为什么能够进行“编译”的python还是“动态语言”。通常,我们都将这两个词作为一对反义词——“动态语言”1包括Python、Ruby和 Javascript等,而“编译语言”则包括C、Java和Haskell等。

人们通常所说的“编译语言”是指能够编译出适用于x86、ARM等的指令2(作用于真正的机器)的语言。一种“解释性”语言不是根本就没有编译器3就是只编译成一个中间表示,比如字节码。字节码的指令不是作用于任何硬件的,而是虚拟机。Python就属于后者:Python的编译器将生成的字节码传递给Python解释器。4

Python解释器将通过虚拟机做许多工作使得字节码得以解释。至于虚拟机,我们会在第五部分讨论。

目前为止,我们对编译和解释的概念还是抽象的。通过下面这个例子我们能更加清晰:

12345678910 >>> def modulus(x, y):...     return x % y...>>> [ord(b) for b in modulus.func_code.co_code][124, 0, 0, 124, 1, 0, 22, 83]>>> dis.dis(modulus.func_code)  2           0 LOAD_FAST                0 (x)              3 LOAD_FAST                1 (y)              6 BINARY_MODULO              7 RETURN_VALUE

这是一个函数以及它的字节码通过反汇编程序的结果。一旦我们定义了modulus函数,它就被编译了并且生成了一个不能被修改的代码对象。

这应该很容易推算。键入modulus(%)使编译器发出指令BINARY_MODULO。所以如果我们要计算一个余数的话,这个函数就能够发挥作用了。

12 >>> modulus(15,4)3

这样看,它正常工作。但如果我们不传递数字给它呢?

12 >>> modulus(\”hello %s\”, \”world\”)\’hello world\’

慢着,这是怎么了?你以前也许见到过,但它通常是这么写的:

12 >>> print \”hello %s\” % \”world\”hello world

当BINARY_MODULO处理两个字符串的时候,它默认执行字符串插值而不是求余数。这就是动态类型的典型例子。编译器在生成modulus的代码对象的时候,它完全不知道x和 y是字符串、数字还是其它类型。它只是发出一些指令而已:加载一个名字,加载另一个名字,BINARY_MODULO这个两个对象,然后返回结果。至于弄清BINARY_MODULO真正指什么则是解释器的工作。

我想我们忽略了一些东西。我们的函数modulus能够计算余数或者格式化字符串,还有吗?如果我们定义一个能够响应__mod__的自定义对象的话,我们还能做很多。

1234567891011121314 >>> class Surprise(object):...     def __init__(self, num):...         self.num = num...     def __mod__(self, other):...         return self.num + other.num...>>> seven = Surprise(7)>>> four = Surprise(4)>>> modulus(seven, four)11>>> modulus(7,4)3>>> modulus(\”hello %s\”, \”world\”)\’hello world\’

虽然还是那个有着同样字节码的函数modulus,但是当它传递不同种对象的时候,作用并不相同。Modulus也可能报错——比如,如果我们使用一个不能执行__mod__的对象就会有TypeError。更不可思议的是,当__mod__被调用的时候,我们能写出一个造成SystemExit的自定义对象。__mod__函数能够对文件进行写入操作;改变一个全局变量或者删除对象的另外一个性质。我们几乎能做任何事。

这也是难以优化Python的原因之一:在编译代码对象和生成字节码的时候,你并不知道会有怎样的结果。编译器根本不关心结果如何。就像Russell Power 和 Alex Rubinsteyn 所说的:“我们能使解释性语言Python有多快?”,“由于不用声明类型信息,几乎每个指令都要像INVOKE_ARBITRARY_METHOD一样来执行。”

尽管“编译”和“解释”的定义在通常情况下是很难区分的,但是对于Python来说却很简单。编译工作就是生成代码对象,包括字节码。而翻译的工作就是翻译字节码,执行指令。Python保持“动态”特性的原因之一就是同样的字节码能够有不同的作用。更普遍的说法就是Python解释器的工作比编译器的多一些。

在第五部分,我们就会讨论虚拟机和解释器了。

注:

  1. 你通常听到的“解释语言”就是“动态语言”。
  2. 感谢David Nolen给出了这个定义。“语法分析”、“编译”和“解释”的定义很易混淆。
  3. 一些语言并不在R、Scheme、二进制文件中都进行编译。这与你使用的开发工具和你对“编译”的定义有关。
  4. 尽管我和以往一样是基于CPython 和Python 2.7来写本文的,但是本文大部分内容也适于其它开发工具。

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...