python解释器简介_Python解释器简介(4):动态语言

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

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

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

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

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

Python

1

2

3

4

5

6

7

8

9

10

>>>defmodulus(x,y):

...returnx%y

...

>>>[ord(b)forbinmodulus.func_code.co_code]

[124,0,0,124,1,0,22,83]

>>>dis.dis(modulus.func_code)

20LOAD_FAST0(x)

3LOAD_FAST1(y)

6BINARY_MODULO

7RETURN_VALUE

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

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

Python

1

2

>>>modulus(15,4)

3

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

Python

1

2

>>>modulus("hello %s","world")

'hello world'

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

Python

1

2

>>>print"hello %s"%"world"

hello world

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

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

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

>>>classSurprise(object):

...def__init__(self,num):

...self.num=num

...def__mod__(self,other):

...returnself.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解释器的工作比编译器的多一些。

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

注:

你通常听到的“解释语言”就是“动态语言”。

感谢David Nolen给出了这个定义。“语法分析”、“编译”和“解释”的定义很易混淆。

一些语言并不在R、Scheme、二进制文件中都进行编译。这与你使用的开发工具和你对“编译”的定义有关。

尽管我和以往一样是基于CPython 和Python 2.7来写本文的,但是本文大部分内容也适于其它开发工具。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值