Python 解释器

Python 语言快速入门,为项目 4 用 Scheme 编写 Python 解释器做准备。

Python 简介

我们将学习 Python,也就是 CS61A 课程使用的语言。CS61A 的同学们正在用 Python 编写一个 Scheme 解释器。而在 CS61AS 这门课里,你的最后一个项目将是用 Scheme 写一个 Python 解释器(Python interpreter)。

打开 Python

要打开 Python,进入终端输入 “python”,随后会出现 ”>>>” 提示符,它相当于 Scheme 的 ”->”。

稍后你会发现,Python 中的空格非常重要。对 Python 而言,空格的地位相当于 Scheme 的圆括号。

玩转 Python

在解释器里试试下面这些命令。其中大部分来自项目说明文档,另外补充了一些例子。有些例子是故意会报错的。如果你遇到意料之外的行为,请提问!

print

怎么让 Python 打印 “Hello World” 呢?就这样:

>>> print "Hello World"
Hello World

就这样!(真的,没骗你)。从这个简单的例子你可能已经注意到,Python 调用函数不需要左圆括号,print 前面不需要加左括号。Python 区分大小写,所以 “PRINT” 不行。另一个关键区别是:Python 只支持中缀运算符,运算符位于其运算数之间:

>>> print 2 + 2
4

其实你不一定需要 print 语句;解释器会自动求值你在提示符下输入的任何内容,它使用一个读取-求值-打印循环(Read-Eval-Print loop),与元循环求值器所用的循环非常相似(再过两节我们会探讨它)。例如:

>>> 2 + 2
4

下面这些的输出是什么?

>>> 3 + 1 - 5 * 1
>>> 3 + (1 - 5) * 1
>>> 10/2
>>> 10/0
>>> (5+1)
>>> (10)

赋值

Python 中的赋值与其他语言类似。例如,如果你想把一个值赋给名为 x 的变量:

>>> x = 2
>>> print x
2

与 Scheme 不同,Python 不区分 DEFINE 和 SET!。如果变量 x 尚不存在,上述赋值就在全局环境中创建一个新变量 x;否则,x 的原有值会被覆盖。

试试下面这些:

>>> num
>>> num = 3
>>> num
>>> num = num + 1
>>> num
>>> num = "Berkeley"
>>> num

布尔值

「既然用 ”=” 赋值,那怎么判断相等呢?」Python(以及大多数其他语言)用 ”==” 代替。

试试下面这些:

>>> 5 == 1
>>> 5 == 5
>>> 5 = 5
>>> x = 10
>>> x == 5
>>> x == 10
>>> x == x

Python 支持布尔运算符 and 和 or,它们的行为与对应的 Scheme 特殊形式完全一致:

>>> x = 3
>>> (x == 3) and (x == 4)
False
>>> True and 3 and 5
5
>>> True and 3 and False
False
>>> True or 3 or False
True

Python 中对应 #t 和 #f 的分别是 True 和 False(大小写很重要)。

试试下面这些:

>>> True and True and False
>>> True and True and True
>>> (1 == 0) and (42 == 42)
>>> (1 == 1) and (42 == (1 / 0))
>>> (1 == 0) and (42 == (1 / 0))
>>> 2 and 3 and 4
>>> (1 == 0) or (42 == (1 / 0))
>>> (1 == 1) or (42 == (1 / 0))
>>> True or 5
>>> False or 5
>>> 5 or True
>>> 10 or 5
>>> False or (1 == 0) or 5
>>> not True
>>> not False
>>> not (1==0)
>>> not 5
>>> not "world"
>>> not ""

表

Python 有表(list)!(它怎么会没有呢?)

>>> x = [1, 2, 3]

现在 x 是一个存储着三个数的表的变量。你大概猜到了,它相当于 Scheme 里的 (list 1 2 3)。Python 的表也可以是嵌套的:

>>> x = [[1, 2, 3], 2, 3]

可惜,我们不能对 Python 的表用 CAR 或 CDR。要访问表中的特定元素:

>>> x[1]
2

记法 “x[1]” 返回表中的第二个元素(Python 使用从零开始的计数)。同样,这里可以把 ”[” 看作一个中缀运算符。

试试下面这些:

>>> [0,1,3,-1,5]
>>> lst = [0,1,3,-1,5]
>>> lst
>>> 0 in lst
>>> 4 in lst
>>> 0 not in lst
>>> 4 not in lst
>>> newlst = ["hey","I am", "a list", "too", ["boo", 100]]
>>> newlst
>>> "hey" in newlst
>>> "am" in newlst
>>> newlst[0]
>>> newlst[0] == "hey"
>>> newlst[1]
>>> newlst[4]
>>> newlst[5]

语句块

If 语句

Python 有一个重要特点,源于它对代码可读性的追求,那就是缩进(INDENTATION)的使用。在包括 Scheme 在内的大多数其他语言中,缩进无关紧要,因为这些语言不在乎有多少个空格,只用空格来分隔符号、数和单词。而在 Python 中,一行开头的空格数是重要的。

>>> x = 2
>>> if x == 1:
...   x = x + 1
...   print x

(在紧接着出现的 ”…” 提示符后,你需要再按一次 ENTER 键,表示 if 语句输入完毕。)Python 的 if 语句与 Scheme 中的对应形式工作原理相同:如果 if 语句的条件满足,就求值语句体。注意我们用了 ”==” 而不是 ”=“:因为 ”=” 已用于赋值,所以用 ”==” 判断相等。还要注意语句体是缩进的:语句体中的所有语句必须以相同的缩进开头。因此,下面这样是不行的:

>>> x = 2
>>> if x > 1:
...   x = x + 1
...    print x

因为语句体中的第二条语句比第一条缩进得更多。类似地,下面这样也不行:

>>> x = 2
>>> if x > 1:
...    x = x + 1
...   print x

因为语句体中的第二条语句比第一条缩进得更少。一般来说,只有当你结束一组相关语句(即一个语句块,BLOCK)时,才应该减少缩进(DEDENT)。一个语句块中的所有语句必须以相同数量的空格缩进。再举一个例子,if 语句还可以有 else 子句,当条件不满足时求值它。

>>> x = 2
>>> if x > 1:
...   x = x + 1
...   print x
... else:
...    x = x - 1
...    print x

注意,if 语句及其 else 子句对应语句块内部的行缩进量相同,但两个块本身的缩进量不同(虽然也可以相同!)。不过,if 语句和 else 子句的缩进量必须相同,因为它们属于同一条语句。然而,所有不属于语句块或子语句块的语句都不应有缩进。在 Python 解释器提示符下试试下面这条语句(它在 ”>>> ” 之后有两个空格的缩进):

>>>   2 + 3

缩进能强制写出整洁的代码,但可能需要一段时间才能习惯;关键是记住:只有开始一个新的语句块时才需要缩进。

试试下面这些:

>>> if x == 3:
...   print x + 1
... elif x < 4:
...   print x + 2
... elif x > 5:
...   print x + 3
... else:
...   print x + 4

定义函数

Python 也有函数(FUNCTIONS),它相当于 Scheme 的过程。下面定义了 square 函数:

>>> def square(x):
...   return x * x

(同样,在紧接着出现的 ”…” 提示符后,你需要再按一次 ENTER 键,表示过程体输入完毕。)这个语法与 C 类语言相似:函数的实参写在函数名后面的圆括号里。调用函数:

>>> square(3)
9

从这个意义上说,左圆括号可以看作一个中缀运算符,运算符位于其运算数之间。要理解这一点,回忆一下:在 Scheme 中,左圆括号可以看作前缀运算符,它把第一个实参「调用」在后续实参上。类似地,在 Python 中,左圆括号把第一个实参(square)「调用」在下一个实参(3)上。另外,如果 Python 过程需要返回值,我们必须在函数体中显式添加 return 语句来返回结果;相比之下,在 Scheme 中,过程定义的最后一行总是被返回。这让我们可以区分两类 Python 函数:一类返回值,另一类不返回值、主要用于其副作用:

>>> def foo():
...   print "Hello World"

试试下面这些:

>>> def sum_of_squares(x,y):
...   return square(x) + square(y)
>>> sum_of_squares(3,4)
>>> square(square(2))

循环

Python 有循环结构。项目说明文档中有更详细的解释,但先试试下面这些代码:

while

while 循环接受一个谓词,只要谓词求值为 False,就会继续求值循环体。

>>> x = 3
>>> while x < 5:
...   print x
...   x = x + 1
>>> y = 1
>>> while y < 50:
...   print y
...   y = y*2

for

for 循环接受一个表(或任何序列),用序列中的每个元素依次执行循环体。这类似于你在第 9 课学过的循环。

>>> for i in [1, 3, 5, 2, 4]:
     ...   print i
>>> for wd in ["Twinkle","twinkle","little","stars"]:
...   print wd