大家看到什么翻译错误,格式错误,或是感觉可以有更好的翻译的,欢迎大家直接参与翻译 (如果是修改,你可以在已有翻译的旁边标注一下。),谢谢 ;-)

附录 —— python精要

如果你是第一次接触 python 的话,那建议你去看看 Guido van Rossum 写的 Python Tutorial ,你可以在 http://python.org/ 上下到这本书。 或者你也可以从那几本优秀的针对 python 初学者的书中选一本来进行学习。 我在序言里面说过,这本书针对的读者会不太一样。

就像上面说的那样,本书的读者可能只是平时不怎么用 python 而已, 也可能只是有一段时间没接触 python 了, 还可能是已经精通好几们其它语言了, 总之对他们来说只要对 python 语言简要扼要地概括一下就足够了。 本附录便会简明扼要地谈谈 python 语言每一个重要的组成部分, 但不会涉及任何库 (甚至包括标准库和本书主要章节中讨论过的常用库)。 也不会覆盖语法语义的所有细节。 不过,这篇文章对于理解本书的例子来说应该是足够了。

甚至连那些对 python 已经很熟悉了的读者都有可能会喜欢上这篇文章呢! 本文的目的与大部分介绍文章都不一样。 我相信我对语言特色进行的这种分类和解释的方式能为您提供一个新鲜的——也是准确的——看待 python 语言的视角。 甚至连 python 程序员看完这篇文章后,都可能会对自己经常使用且熟知的那些东西有一些新的看法。 这篇附录不会刻意去回避一些计算机科学中的抽象术语——如果你对某一术语不熟,大可直接跳过那一段, 这并不会让你错过太多; 某些术语在术语表中还会有简短的解释。

python 属于哪种类型的语言

python 是一们字节码编译型的语言,它支持多种编程范式。 由于运行一个 python 程序不需要单独的编译步骤, 所以有时候 python 也被叫做是解释型语言或是脚本语言; 用更精确的术语来说,python 是使用一个虚拟机 (就像 Java 或是 Smalltalk 那样) 来执行一组抽象机器的指令。 大部分情况下,一个被编译成了字节码的程序会被缓存起来, 这样以后再运行的话速度就会更快。 而且不管在什么地方进行的编译过程都是在“幕后”悄悄进行的。

用最宽泛的术语来说,python 是一们命令式的而非声明式 (函数式或逻辑式) 的编程语言。 python 是动态类型兼强类型的语言,相对大部分语言来说它拥有真正的迟绑定。 另外 python 还是一们拥有强大内省机制的面向对象语言, 它是通过约定而非强制机制来进行访问控制和名字的可见性控制的。 撇开它的面向对象的核心,python 大部分语法都被设计成方便的过程式风格, 并通过这些语法来展现核心的面向对象机制。 (? 虽然 python 允许基本的函数式编程 (FP) 技术,不过边界效应 (side effects) 还是正常的 (norm), 求值也总是严格的,而且还不会对尾递归(还有几乎所有其它的东西)进行编译器优化。 )

python 有一个不大的保留字集合, (? 还有分界块 (delimits blocks), ) 其代码结构仅基于缩进, 还拥有一组相当丰富的内置数据结构。 相对其它语言来说 python 很简洁,可读性很强。 另外 python 的强大很大程度上来源于它的标准库和它灵活的模块系统。

名字空间与绑定

用 python 编程要掌握的一个最重要概念就是名字空间了。 python 程序中的每一个执行环境 (或者说作用范围) 都拥有一组层次结构的名字空间; 每一个名字空间都包含着一组名字,每一个名字都绑定到一个对象。 老版本的 python 使用 “三层范围规则” (内置/全局/局部) 对名字空间进行组织, 不过从 python 2.1 开始就增加了词法嵌套作用范围。 不过大部分情况下你并不需要考虑这种微妙的东西, 况且作用范围工作的方式完全符合我们的直觉。 (大部分需要用到词法作用范围的特例都是嵌套函数或是嵌套类)

要在当前的名字空间或其它的名字空间中将一个名字绑定到一个对象上去, 有好几种方法可以用,这些方法有:

赋值和解除引用

x=37y="foo" 这样的 python 表达式干了好几件事: 首先如果该对象—— 比方说 37 或是 "foo" ——不存在,python 就会创建这个对象。 如果该对象已存在,python 就先找到它。 然后,如果名字 xy 不存在的话,就先把它们加到当前名字空间中来, 并将这个名字绑定到相应的对象。 如果该名字在当前名字空间中已经存在,那它就会被重新绑定。 多个名字,甚至是处在多个名字空间中的多个名字,都可以绑定到同一个对象。

一个简单的赋值语句就是对当前名字空间中的名字进行绑定,除非该名字已经被定义成 global 了。 而一个被定义成 global 的名字则被绑定到全局 (也就是模块级的) 名字空间中。 在赋值语句左边使用 . 号限制的名字会将绑定一个指定的名字空间中的名字——可能是对象的属性,也可能是模块/包的名字空间, 比如:

   1 >>> x = "foo"              # 将 `x` 绑定到全局名字空间
   2 >>> def myfunc():          # 将 `myfunc` 绑定到全局名字空间
   3 ...     global x, y        # 为 `x`, `y` 指定名字空间
   4 ...     x = 1              # 将全局名字 `x` 重绑定到对象 1
   5 ...     y = 2              # 创建全局名字 `y` 和对象 2
   6 ...     z = 3              # 创建局部名字 `z` 和对象 3
   7 ...
   8 >>> import package.module  # 绑定名字 `package.module`
   9 >>> package.module.w = 4   # 将 `w` 绑定到名字空间 `package.module`
  10 >>> from mymod import obj  # 将名字 `obj` 导入到全局名字空间
  11 >>> obj.attr = 5           # 绑定 `obj` 对象的名字空间中的名字 `attr` 

无论一个名字(包括用 . 号限制了的)何时出现在赋值语句的右边或是只包含它自己的代码行中, 该名字都会被解除引用而返回它所引用的对象。 如果一个名字不处在某个可访问的名字空间里面,它就不能被解除引用; 试图这样做的话会抛出一个 NameError 异常。 如果名字后面跟着左右两个小括号 (括号中间可能还包含着以逗号分割的表达式), 那么对该名字解除引用后,相应的对象会被调用。调用过程中实际干些什么事情可以由 python 对象控制和重写。 不过通常调用函数或方法会去执行一些代码,而调用 class 则会创建一个实例对象。 比如:

   1 >>> pkg.subpkg.func()   # 从一个名字空间中调用一个函数
   2 >>> x = y               # 对 `y` 解除引用并绑定该对象给 `x`

函数和类的定义

要描述一个对象并同时将它绑定到一个名字上去的首选方式就是定义一个函数或者是类了。 其实 defclass 声明语句本质上只是赋值的不同形式罢了。 对于函数来说,我们还可以在赋值语句的右边使用 lambda 运算符,这样可以给名字绑定一个“匿名”函数。 而类并没有和它等价的便捷技术,但是总得来说类和函数的声明还是很相似的:

   1 >>> add1 = lambda x,y: x+y # 在全局名字空间中给 `add1` 绑定一个函数
   2 >>> def add2(x, y):        # 在全局名字空间中给 `add2` 绑定一个函数
   3 ...     return x+y
   4 ...
   5 >>> class Klass:           # 给名字 `Klass` 绑定一个类对象
   6 ...    def meth1(self):    # 给名字空间 `Klass` 中的 `meth1` 绑定一个函数
   7 ...        return `Myself`

import 表达式

导入——或从某处导入——一个模块或者一个包时,会在当前名字空间中添加或修改一些名字绑定。 import 表达式有两种形式,每一种都有稍微不同的效果。

一种是这样的:

   1 >>> import modname
   2 >>> import pkg.subpkg.modname
   3 >>> import pkg.modname as othername

它会在当前名字空间中增加一个新的模块对象。 这些模块对象本身定义有自己的名字空间,你可以绑定值到其中,也可以使用其中的对象。

另一种是这样的:

   1 >>> from modname import foo
   2 >>> from pkg.subpkg.modname import foo as bar

它会向当前名字空间添加名字 foobar在这两种 import 形式之中,被导入模块中所有的表达式都会被执行—— 区别只在于对当前名字空间产生的效果。

这是 import 表达式另一种更特殊的形式:

   1 >>> from modname import *

其中的星号不是 glob 通配符也不是正则模式,它是一个特殊的语法形式。 "import star" 会将模块名字空间中所有名字全部导入到当前名字空间中来 (除了那些以下划线开头的名字,不过它们还是可以被显示地导入)。 我们不太提倡这种形式的 import ,因为它可能会添加一些你明显并不需要的名字到当前名字空间, 还有可能会重新绑定已有的名字。

for 表达式

虽然 for 是用来建立循环的,但实际上它是通过将一个可迭代 对象中的连续元素不断绑定到(当前名字空间中的)一个名字 来实现的。以下语句 (几乎) 是等价的:

   1 >>> for x in somelist:  # 用 `for` 进行重复的绑定
   2 ...     print x
   3 ...
   4 >>> ndx = 0             # 如果 `bdx` 定义过,则重绑定之
   5 >>> while 1:            # 在 `while` 中重复绑定
   6 ...    x = somelist[ndx]
   7 ...    print x
   8 ...    ndx = ndx+1
   9 ...    if ndx >= len(somelist):
  10 ...        del ndx
  11 ...        break

except 表达式

except 表达式中也可以将一个名字绑定到一个异常参数上:

   1 >>> try:
   2 ...     raise "ThisError", "some message"
   3 ... except "ThisError", x:    # 将 `x` 绑定到异常参数上
   4 ...     print x
   5 ...
   6 some message

数据类型

python 有一组丰富的基本数据类型。所有 python 的 collection 类型 都可以在其中包含不同类型的元素,甚至其它 collection 类型 (会稍微有点限制)。 因此,在 python 中构建复杂数据结构变得非常简单。

和许多其他语言都不一样的是,python 的数据类型分为两种:可变的和不可变的。 所有原子数据类型都是不可变的数据类型,还有 collection 类型 tuple 也是属于这一类的。 而 collection 类型 listdict 是可变的,还有类、实例也都是属于这一类的。 所谓数据类型的可变性指的就是该类型的对象是否可以“就地” (in-place) 修改—— 不可变的对象就只能够对它们进行创建和销毁,不可以在它们存在的期间中进行修改。 这种区别导致的一个结果就是不可变对象可以作为字典的 key,而可变对象则不能。 导致的另外一个结果就是如果一个数据结构——特别是很大的数据结构—— 需要在程序操作期间经常被修改,那你就应该选择一个可变的数据结构了(通常是一个 list)。

大部分时候,如果你想在不同 python 数据类型之间对值进行转换, 需要显示地进行转换(或者说编码)调用, 不过数值类型包含有提升 (promotion) 规则, 可以允许数值表达式中混合多种类型。 下面列出所有内置数据类型和相关的讨论。 内置函数 type() 可以用来查看一个对象的类型。

简单类型

字符串格式替换(Interpolation)

字面上的 (Literal) 字符串和 unicode 字符串可以包含内嵌的格式码。 如果字符串包含有格式码,那么使用 % 运算符和一个给出用来替换的值的元组 (tuple) 或者字典就可以向字符串中插入值。

包含格式码的字符串可以有两种模式。 简单点的模式是通过这种语法 %[标记][长度[.精度]]<类型> 来使用格式码。 在这种模式下的字符串需要一个 % 外加一个相应长度和相应数据类型组成的元组来 对字符串进行替代。如果只有一个值被替代,你还可以直接给出这个值, 就不需要写一个长度为1的元组了。比如:

   1 >>> "float %3.1f, int %+d, hex %06x" % (1.234, 1234, 1234)
   2 'float 1.2, int +1234, hex 0004d2'
   3 >>> '%e' % 1234
   4 '1.234000e+03'
   5 >>> '%e' % (1234,)
   6 '1.234000e+03'

稍微复杂点的模式是给格式码内嵌一个名字, 随后它会被作为替代字典的 key。 这个模式的语法是 %(key)[标记][长度[.精度]]<类型>对这种形式的字符串进行替代需要一个 % 外加一个字典, 这个字典的 key 中要包含了所有名字,并且名字对应的值要拥有相应的数据类型。 比如:

   1 >>> dct = {'ratio':1.234, 'count':1234, 'offset':1234}