超级--python教程


Python 手册 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/index.html[09-5-21 ••08:00:58] Python中文社区 Python 手册 向上:Python 文档索引 向后:前言 Python 手册 Guido van Rossum Fred L. Drake, Jr., editor PythonLabs Email: python-docs@python.org Release 2.3 July 29, 2003 前言 目录 1. 开胃菜 2. 使用Python解释器 2.1 调用解释器 2.1.1 传递参数 2.1.2 交互模式 2.2 解释器及其工作模式 2.2.1 错误处理 2.2.2 执行 Python 脚本 2.2.3 源程序编码 2.2.4 交互环境的启动文件 3.初步认识 Python 3.1 像使用计算器一样使用Python 3.1.1 数值 3.1.2 字符串 3.1.3 Unicode 字符串 3.1.4 链表 3.2 开始编程 4. 流程控制 4.1 if 语法 4.2 for 语法 4.3 range() 函数 4.4 break 和 continue 语法以及 else 子句 在循环中的用法 4.5 pass 语法 4.6 定义函数 4.7 定义函数的进一步知识 4.7.1 定义参数变量 4.7.2 参数关键字 Python 手册 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/index.html[09-5-21 ••08:00:58] 4.7.3 可变参数表 4.7.4 Lambda 结构 4.7.5 文档字符串 5. 数据结构 5.1 深入链表 5.1.1 将链表作为堆栈来使用 5.1.2 将链表作为队列来使用 5.1.3 函数化的编程工具 5.1.4 链表的内含(Comprehensions) 5.2 del 语法 5.3 Tuples 和 Sequences 5.4 字典(Dictionaries) 5.5 循环技巧 5.6 深入条件控制 5.7 Sequences 和其它类型的比较 6. 模块 6.1 深入模块 6.1.1 模块搜索路径 6.1.2 “编译” Python 文件 6.2 标准模块 6.3 dir() 函数 6.4 包 6.4.1 从包中导入所有内容(import * ) 6.4.2 隐式包引用 6.4.3 包中的多重路径 7. 输入和输出 7.1 格式化输出 7.2 读写文件 7.2.1 文件对象的方法 7.2.2 pickle 模块 8. 错误和异常 8.1 语法 Errors 8.2 异常 8.3 捕获异常 8.4 释放异常 8.5 用户自定义异常 8.6 定义 Clean-up Actions 9. 类 9.1 一个术语 9.2 Python 的生存期和命名空间 9.3 类(Classes)的初步印像 9.3.1 类定义语法 9.3.2 类对象 9.3.3 实例对象 9.3.4 方法对象 9.4 自由标记(Random Remarks) 9.5 继承 9.5.1 多继承 Python 手册 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/index.html[09-5-21 ••08:00:58] 9.6 私有变量 9.7 零杂技巧 9.8 异常也是类 9.9 迭代子(Iterators) 9.10 发生器(Generators) 10. 接下来? A. 交互式编辑和历史回溯 A.1 行编辑 A.2 历史回溯 A.3 快捷键绑定 A.4 注释 B. 浮点计算:问题与极限 B.1 表达错误 C. 历史和授权 C.1 本软件的历史 C.2 修改和使用Python的条件(Terms and conditions for accessing or otherwise using Python) 关于本文档 Python 手册 向上:Python 文档索引 向后:前言 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 前言 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node1.html[09-5-21 ••08:01:00] Python中文社区 Python 指南 向前:Python 指南 向上: Python 指南 向下:目录 前言 Copyright © 2001, 2002, 2003 Python Software Foundation. All rights reserved. Copyright © 2000 BeOpen.com. All rights reserved. Copyright © 1995-2000 Corporation for National Research Initiatives. All rights reserved. Copyright © 1991-1995 Stichting Mathematisch Centrum. All rights reserved. See the end of this document for complete license and permissions information. 概要: Python 是一种容易学习的强大语言。 它包括了高效的高级数据结构,提供了一个简单但很有有效的方式以便 进行面向对象编程。Python 优雅的语法,动态数据类型,以及它的解释器,使其成为了大多数平台上应用于各 领域理想的脚本语言以及开发环境。 Python解释器及其扩展标准库的源码和编译版本可以从Python的Web站点http://www.python.org/及其所有镜像 站上免费获得,并且可以自由发布。该站点上也提供了Python的一些第三方模块,程序,工具,以及附加的文 档。 Python的解释器很容易通过C或C++(或者其它可以由C来调用的语言)来实现功能和数据结构的扩展。因 些Python 也很适于做为定制应用的一种扩展语言。 这个手册介绍了一些Python语言及其系统的基本知识与根念。这有助于对Python有一个基本的认识,当然所有 的例子都包括在里面了,所以这本手册很适合离线阅读。 需要有关标准对象和模块的详细介绍的话,请查询Python 程序库参考手册 文档。Python 参考手册 提供了更多 的关于语言方面的正式说明。需要编写C或C++扩展,请阅读 Python 解释器的扩展和集成 以及Python/C API 参 考手册。 这几本书涵盖了各个深度上的Python知识。 本手册不会涵盖Python的所有功能,也不会去解释所用到的所有相关的知识。相反,它介绍了许多Python中最 引人注目的功能,这会对读者掌握这门语言的风格大有帮助。读过它后,你应该可以阅读和编写Python模块和 程序了,接下来你可以从Python 库参考手册中进一步学习Python复杂多变的库和模块了。 Python 指南 向前:Python 指南 向上: Python 指南 向下:目录 前言 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node1.html[09-5-21 ••08:01:00] Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 目录 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node2.html[09-5-21 ••08:01:03] Python中文社区 Python Tutorial 向前:前言 向上:Python 指南 向后 1. 开胃菜 目录 前言 1. 开胃菜 2. 使用Python解释器 2.1 调用解释器 2.1.1 传递参数 2.1.2 交互模式 2.2 解释器及其工作模式 2.2.1 错误处理 2.2.2 执行 Python 脚本 2.2.3 源程序编码 2.2.4 交互环境的启动文件 3.初步认识 Python 3.1 像使用计算器一样使用Python 3.1.1 数值 3.1.2 字符串 3.1.3 Unicode 字符串 3.1.4 链表 3.2 开始编程 4. 流程控制 4.1 if 语法 4.2 for 目录 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node2.html[09-5-21 ••08:01:03] 语法 4.3 range() 函数 4.4 break 和 continue 语法以及 else 子句 在循环中的用法 4.5 pass 语法 4.6 定义函数 4.7 定义函数的进一步知识 4.7.1 定义参数变量 4.7.2 参数关键字 4.7.3 可变参数表 4.7.4 Lambda 结构 4.7.5 文档字符串 5. 数据结构 5.1 深入链表 5.1.1 将链表作为堆栈来使用 5.1.2 将链表作为队列来使用 5.1.3 函数化的编程工具 5.1.4 链表的内含(Comprehensions) 5.2 del 语法 5.3 Tuples 和 Sequences 5.4 字典(Dictionaries) 5.5 循环技巧 5.6 深入条件控制 5.7 Sequences 和其它类型的比较 6. 模块 6.1 深入模块 6.1.1 模块搜索路径 6.1.2 “编译” Python 文件 目录 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node2.html[09-5-21 ••08:01:03] 6.2 标准模块 6.3 dir() 函数 6.4 包 6.4.1 从包中导入所有内容(import * ) 6.4.2 隐式包引用 6.4.3 包中的多重路径 7. 输入和输出 7.1 格式化输出 7.2 读写文件 7.2.1 文件对象的方法 7.2.2 pickle 模块 8. 错误和异常 8.1 语法 Errors 8.2 异常 8.3 捕获异常 8.4 释放异常 8.5 用户自定义异常 8.6 定义 Clean-up Actions 9. 类 9.1 一个术语 9.2 Python 的生存期和命名空间 9.3 类(Classes)的初步印像 9.3.1 类定义语法 9.3.2 类对象 9.3.3 实例对象 9.3.4 方法对象 9.4 自由标记(Random Remarks) 目录 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node2.html[09-5-21 ••08:01:03] 9.5 继承 9.5.1 多继承 9.6 私有变量 9.7 零杂技巧 9.8 异常也是类 9.9 迭代子(Iterators) 9.10 发生器(Generators) 10. 接下来? A. 交互式编辑和历史回溯 A.1 行编辑 A.2 历史回溯 A.3 快捷键绑定 A.4 注释 B. 浮点计算:问题与极限 B.1 表达错误 C. 历史和授权 C.1 本软件的历史 C.2 修改和使用Python的条件(Terms and conditions for accessing or otherwise using Python) 关于本文档 Python Tutorial 向前:前言 向上:Python 指南 向后 1. 开胃菜 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 1. 开胃菜 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node3.html[09-5-21 ••08:01:06] Python中文社区 Python 指南 向前:目录 向上:Python 指南 向后:2. 使用 Python 1. 开胃菜 如果你写过大规模的Shell脚本,应该会有过这样的体会:你还非常想再加一些别的功能进去,但它已经太大、 太慢、太复杂了;或者这个功能需要调用一个系统函数,或者它只适合通过C来调用……通常这些问题还不足 以严肃到需要用C重写这个Shell;可能这个功能需要一些类似变长字符串或其它一些在Shell脚本中很容易找到 的数据类型(比如文件名的有序列表),但它们用C来实现就要做大量的工作,或者,你对C还不是很熟悉。 另一种情况:可能你需要使用几个C库来工作,通常C的编写/编译/测试/重编译周期太慢。你需要尽快的开发软 件。也许你需要写一个使用扩展语言的程序,但不想设计一个语言,并为此编写调试一个解释器,然后再把它 集成进你的程序。 遇到以上情况,Python可能就是你要找的语言。Python很容易上手,但它是一门真正的编程语言,提供了 比Shell多的多的结构,支持大型程序。另一方面,它提供了比C更多的错误检查,并且,做为一门高级语言, 它拥有内置的高级数据类型,例如可变数组和字典,如果通过C来实现的话,这些工作可能让你大干上几天的 时间。因为拥有更多的通用数据类型,Python适合比Awk甚至Perl更广泛的问题领域,在其它的很多领 域,Python至少比别的语言要易用得多。 Python可以让你把自己的程序分隔成不同的模块,这样就可以在其它的Python程序中重用。这样你就可以让自 己的程序基于一个很大的标准模块集或者用它们做为示例来学习Python编程。Python中集成了一些类似文 件I/O,系统调用,sockets,甚至像Tk这样的用户图形接口。 Python是一门解释型语言,因为不需要编译和链接的时间,它可以帮你省下一些开发时间。解释器可以交互式 使用,这样就可以很方便的测试语言中的各种功能,以便于编写发布用的程序,或者进行自下而上的开发。还 可以当它是一个随手可用的计算器。 Python可以写出很紧凑和可读性很强的程序。用Python写的程序通常比同样的C或C++程序要短得多,这是因为 以下几个原因: 高级数据结构使你可以在一个单独的语句中表达出很复杂的操作; 语句的组织依赖于缩进而不是begin/end块; 不需要变量或参数声明。 Python是可执行的:如果你会用C语言写程序,那就可以很容易的为解释器添加新的集成模块和功能,或者优 化瓶颈,使其达到最大速度,或者使Python能够链接到所需的二进制架构上(比如某个专用的商业图形库)。 等你真正熟悉这一切了,你就可以把Python集成进由C写成的程序,把Python当做这个程序的扩展或命令行语 言。 顺便说一下,这个语言的名字来源于BBC的“Monty Python's Flying Circus”节目,和凶猛的爬虫没有任何关 系。在文档中引用Monty Python典故不仅是允许的,而且还受到鼓励! 1. 开胃菜 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node3.html[09-5-21 ••08:01:06] 现在你已经了解了Python中所有激动人心的东西,大概你想仔细的试试它了。学习一门语言最好的办法就是使 用它,你会很乐于这样做。 下一节中,我们会很机械的说明解释器的用法。这没有什么神秘的,不过有助于我们练习后面展示的例子。 本指南其它部分通过例子介绍了Python语言和系统的各种功能,开始是简单表达式、语法和数据类型,接下来 是函数和模块,最后是诸如异常和自定义类这样的高级内容。 Python 指南 向前:目录 向上:Python 指南 向后:2. 使用 Python Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 2. 使用Python解释器 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node4.html[09-5-21 ••08:01:08] Python中文社区 Python 手册 向前:1. 开胃菜 向上:Python 手册 Next: 3. 非正式入门指导 子目录 2.1 调用解释器 2.1.1 参数传递 2.1.2 交互模式 2.2 解释器和它的环境 2.2.1 错误处理 2.2.2 执行Python脚本 2.2.3 源程序编码 2.2.4 交互环境的启动文件 2. 使用Python解释器 2.1 调用解释器 通常Python的解释器被安装在目标机器的 /usr/local/bin/python 目录下;把 /usr/local/bin 目录放进你的UNIX Shell 的搜索路径里,确保它可以通过输入 python 来启动。因为安装路径是可选的,所以也有可能安装在其它位置,你可以与安装Python的用户或系统管理员联 系。(例如,/usr/local/python就是一个很常见的选择) 输入一个文件结束符(UNIX上是Ctrl+D,Windwos上是Ctrl+Z)解释器会以0值退出(就是说,没有什么错 误,正常退出--译者)。如果这没有起作用,你可以输入以下命令退出:“import sys; sys.exit()”。 解释器的行编辑功能并不很复杂。装在Unix上的解释器可能会有GNU readline 库支持,这样就可以额外得到精 巧的交互编辑和历史记录功能。可能检查命令行编辑器支持能力最方便的方式是在主提示符下输入Ctrl+P。如 2. 使用Python解释器 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node4.html[09-5-21 ••08:01:08] 果有嘟嘟声(计算机扬声器),说明你可以使用命令行编辑功能,从附录 A 可以查到快捷键的介绍。如果什么 也没有发声,或者P显示了出来,说明命令行编辑功能不可用,你只有用退格键删掉输入的命令了。 解释器的操作有些像Unix Shell:使用终端设备做为标准输入来调用它时,解释器交互的解读和执行命令,通过 文件名参数或以文件做为标准输入设备时,它从文件中解读并执行脚本。 启动解释器的第三个方法是“python -c command [arg] ...”,这种方法可以在命令行中直接执行语句,等同 于Shell的 -c选项。因为Python语句通常会包括空格之类的特殊字符,所以最好把整个语句用双引号包起来。 注意“python file”和“python >> ”);继续的部分被称为从属提示符,由三个点标识(“... ”)。在第一行之前,解释器打 印欢迎信息、版本号和授权提示: python Python 2.3 (#1, Jul 30 2003, 23:22:59) [GCC 3.2 20020927 (prerelease)] on cygwin Type "help", "copyright", "credits" or "license" for more information. >>> 输入多行结构时需要从属提示符了,例如,下面这个 if 语句: >>> the_world_is_flat = 1 >>> if the_world_is_flat: ... print "Be careful not to fall off!" ... Be careful not to fall off! 2.2 解释器及其环境 2. 使用Python解释器 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node4.html[09-5-21 ••08:01:08] 2.2.1 错误处理 有错误发生时,解释器打印一个错误信息和栈跟踪(监视)器?。交互模式下,它返回主提示符,如果从文件 输入执行,它在打印栈跟踪器后以非零状态退出。(异常可以由try语句中的except子句来控制,这样就不会出 现上文中的错误信息) 有一些非常致命的错误会导致非零状态下退出,这由通常由内部矛盾和内存溢出造成。 所有的错误信息都写入标准错误流;命令中执行的普通输出写入标准输出。 在主提示符或附属提示符输入中断符(通常是Control-C or DEL)就会取消当前输入,回到主命令行。2.1执行 命令时输入一个中断符会抛出一个 KeyboardInterrupt 异常,它可以被try句截获。 2.2.2 执行Python脚本 BSD系统中,Python脚本可以像Shell脚本那样直接执行,只要在脚本文件开头写一行命令,指定文件和模式: #! /usr/bin/env python (将用户路径通知解释器) “#!”必须是文件的前两个字符,在某些平台上,第一行必须以Unix风格的行结束符 (“\n”)结束,不能用Mac(“\r”)或Windows(“\r\n”)的结束符。注意,“#”是Python中是行注释的 起始符。 脚本可以通过 chmod 命令指定执行模式和许可权。 $ chmod +x myscript.py 2.2.3 源程序编码 Python的源文件可以通过编码使用 ASCII 以外的字符集。 最好的做法是在 #! 行后面用一个特殊的注释行来定 义字符集。 # -*- coding: iso-8859-1 -*- 根据这个声明,Python会将文件中的字符尽可能的从指定的编码转为Unicode,在本例中,这个字符集是 iso- 8859-1 。在 Python 库参考手册 中可以找到可用的编码列表(根据我的实验,中文似乎只能用cp-936或utf-8,不 直接支持GB,GBK,GB-18030或ISO-10646--译者注)。 如果你的文件编辑器支持UTF-8格式,并且可以保存UTF-8标记(aka BOM - Byte Order Mark),你可以用这 个来代替编码声明(看来至少Jext还不支持这样做,而Vim,我还没找到它的编码设置在哪里,还是老老实实 的用注释行指定源代码的编码吧--译者注)。IDLE可以通过设定Options/General/Default Source Encoding/UTF-8 来支持它。需要注意的是旧版Python不支持这个标记(Python 2.2或更早的版本),也同样不 能使操作系统支持#!文件。 使用UTF-8内码(无论是用标记还是编码声明),我们可以在字符串和注释中使用世界上的大部分语言。标识 符中不能使用非 ASCII 字符集。为了正确显示所有的字符,你一定要在编辑器中将文件保存为UTF-8格式,而 且要使用支持文件中所有字符的字体。 2.2.4 交互式环境的启动文件 2. 使用Python解释器 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node4.html[09-5-21 ••08:01:08] 使用Python解释器的时候,我们可能需要在每次解释器启动时执行一些命令。你可以在一个文件中包含你想要 执行的命令,设定一个名为PYTHONSTARTUP 的环境变量来指定这个文件。这类似于Unix shell的.profile文 件。 这个文件在交互会话期是只读的,当Python从脚本中解读文件或以终端做为外部命令源时则不会如此(尽管它 们的行为很像是处在交互会话期。)它与解释器执行的命令处在同一个命名空间,所以由它定义或引用的一切 可以在解释器中不受限制的使用。你也可以在这个文件中改变sys.ps1和sys.ps2指令。 如果你想要在当前目录中执行附加的启动文件,你可以在全局启动文件中加入类似以下的代码:“if os.path.isfile('.pythonrc.py'): execfile('.pythonrc.py')”。 如果你想要在某个脚本中使用启动文件,必须要在脚本中 写入这样的语句: import os filename = os.environ.get('PYTHONSTARTUP') if filename and os.path.isfile(filename): execfile(filename) 脚注 ... 注:2.1 GNU readline包的一个错误可能会造成无法正常工作。 Python 手册 向前:1. 开胃菜 向上:Python 手册 Next: 3. 非正式入门指导 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] Python中文社区 Python 手册 向前:2. 使用Python解释器 向上:Python 手册 向后: 4. 深入编程 子目录 3.1 初步认识Python 3.1.1 数值 3.1.2 字符串 3.1.3 Unicode 字符串 3.1.4 链表 3.2 开始编程 3. Python的非正式介绍 在后面的例子中,区分输入和输出的方法是看是否有提示符(“>>> ”和“.. ”):想要重复这些例子的话,你 就要在提示符显示后输入所有的一切;没有以提示符开始的行,是解释器输出的信息。需要注意的是示例中的 从属提示符用于多行命令的结束,它表示你需要输入一个空行。 本手册中的很多示例都包括注释,甚至有一些在交互提示符中折行。Python中的注释以符号“#”起始,一直到 当前行的结尾。注释可能出现在一行的开始,也可能跟在空格或程序代码之后,但不会出现在字符串中,字符 串中的#号只代表#号。 示例: # this is the first comment SPAM = 1 # and this is the second comment # ... and now a third! STRING = "# This is not a comment." 3.1 初步认识Python 让我们试验一些简单的Python命令。启动解释器然后等待主提示符“>>> ”出现(这用不了太久)。 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] 3.1.1 数值 解释器的行为就像是一个计算器。你可以向它输入一个表达式,它会返回结果。表达式的语法简明易 懂:+,-,*,/和大多数语言中的用法一样(比如C或Pascal),括号用于分组。例如: >>> 2+2 4 >>> # This is a comment ... 2+2 4 >>> 2+2 # and a comment on the same line as code 4 >>> (50-5*6)/4 5 >>> # Integer division returns the floor: ... 7/3 2 >>> 7/-3 -3 像c一样,等号(“=”)用于给变量赋值。被分配的值是只读的。 >>> width = 20 >>> height = 5*9 >>> width * height 900 同一个值可以同时赋给几个变量: >>> x = y = z = 0 # Zero x, y and z >>> x 0 >>> y 0 >>> z 0 Python完全支持浮点数,不同类型的操作数混在一起时,操作符会把整型转化为浮点数。 >>> 3 * 3.75 / 1.5 7.5 >>> 7.0 / 2 3.5 复数也同样得到了支持,虚部由一个后缀“j”或者“J”来表示。带有非零实部的复数记为“(real+imagj)”,或 者也可以通过“complex(real, imag)”函数创建。 >>> 1j * 1J (-1+0j) >>> 1j * complex(0,1) (-1+0j) >>> 3+1j*3 (3+3j) >>> (3+1j)*3 (9+3j) >>> (1+2j)/(1+1j) (1.5+0.5j) 复数总是由实部和虚部两部分浮点数来表示。可能从 z.real 和 z.imag 得到复数z的实部和虚部。 >>> a=1.5+0.5j >>> a.real 1.5 >>> a.imag 0.5 用于向浮点数和整型转化的函数(float(), int() 和 long())不能对复数起作用--没有什么方法可以将复数 转化为实数。可以使用abs(z)取得它的模,也可以通过z.real得到它的实部。 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] >>> a=3.0+4.0j >>> float(a) Traceback (most recent call last): File "", line 1, in ? TypeError: can't convert complex to float; use e.g. abs(z) >>> a.real 3.0 >>> a.imag 4.0 >>> abs(a) # sqrt(a.real**2 + a.imag**2) 5.0 >>> 交互模式下,最近一次表达式输出保存在_变量中。这意味着把Python当做桌面计算器使用时,它可以更容易 的进行连续计算,例如: >>> tax = 12.5 / 100 >>> price = 100.50 >>> price * tax 12.5625 >>> price + _ 113.0625 >>> round(_, 2) 113.06 >>> 这个变量对于用户来说是只读的。不要试图去给它赋值--由于Python的语法效果,你只会创建一个同名的局 部变量覆盖它。 3.1.2 字符串 除了数值,Python还可以通过几种不同的方法操作字符串。字符串用单引号或双引号标识: >>> 'spam eggs' 'spam eggs' >>> 'doesn\'t' "doesn't" >>> "doesn't" "doesn't" >>> '"Yes," he said.' '"Yes," he said.' >>> "\"Yes,\" he said." '"Yes," he said.' >>> '"Isn\'t," she said.' '"Isn\'t," she said.' 字符串可以通过几种方式分行。可以在行加反斜杠做为继续符,这表示下一行是当前行的逻辑沿续。 hello = "This is a rather long string containing\n\ several lines of text just as you would do in C.\n\ Note that whitespace at the beginning of the line is\ significant." print hello 注意换行用 \n 来表示;反斜杠后面的新行标识(newline,缩写“n”)会转换为换行符,示例会按如下格式打 印: This is a rather long string containing several lines of text just as you would do in C. Note that whitespace at the beginning of the line is significant. 然而,如果我们创建一个“raw”行,\n序列就不会转为换行,示例源码最后的反斜杠和换行符n都会做为字符 串中的数据处理。如下所示: 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] hello = r"This is a rather long string containing\n\ several lines of text much as you would do in C." print hello 会打印为: This is a rather long string containing\n\ several lines of text much as you would do in C. 或者,字符串可以用一对三重引号”””或'''来标识。三重引号中的字符串在行尾不需要换行标记,所有的格 式都会包括在字符串中。 print """ Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to """ produces the following output: Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to 解释器打印出来的字符串与它们输入的形式完全相同:内部的引号,用反斜杠标识的引号和各种怪字符,都精 确的显示出来 。如果字符串中包含单引号,不包含双引号,可以用双引号引用它,反之可以用单引号。(后面 介绍的print语句,可以可以用来写没有引号和反斜杠的字符串)。 字符串可以用+号联接(或者说粘合),也可以用*号循环。 >>> word = 'Help' + 'A' >>> word 'HelpA' >>> '<' + word*5 + '>' '' 两个字符串值之间的联接是自动的,上例第一行可以写成“word = 'Help' 'A'”这种方式只对字符串值有效,任 何字符串表达式都不适用这种方法。 >>> import string >>> 'str' 'ing' # <- This is ok 'string' >>> string.strip('str') + 'ing' # <- This is ok 'string' >>> string.strip('str') 'ing' # <- This is invalid File "", line 1, in ? string.strip('str') 'ing' ^ SyntaxError: invalid syntax 字符串可以用下标(索引)查询;就像C一样,字符串的第一个字符下标是0。这里没有独立的字符类型,字符 仅仅是大小为一的字符串。就像在Icon中那样,字符串的子串可以通过切片标志来表示:两个由冒号隔开的索 引。 >>> word[4] 'A' >>> word[0:2] 'He' >>> word[2:4] 'lp' 切片索引可以使用默认值;省略前一个索引表示0,省略后一个索引表示被切片的字符串的长度。 >>> word[:2] # The first two characters 'He' 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] >>> word[2:] # All but the first two characters 'lpA' 和C字符串不同,Python字符串不能改写。按字符串索引赋值会产生错误。 >>> word[0] = 'x' Traceback (most recent call last): File "", line 1, in ? TypeError: object doesn't support item assignment >>> word[:1] = 'Splat' Traceback (most recent call last): File "", line 1, in ? TypeError: object doesn't support slice assignment 然而,可以通过简单有效的组合方式生成新的字符串: >>> 'x' + word[1:] 'xelpA' >>> 'Splat' + word[4] 'SplatA' 切片操作有一个很有用的不变性: s[:i] + s[i:] 等于s。 >>> word[:2] + word[2:] 'HelpA' >>> word[:3] + word[3:] 'HelpA' 退化的切片索引被处理的很优美:过大的索引代替为字符串大小,下界比上界大的返回空字符串。 >>> word[1:100] 'elpA' >>> word[10:] '' >>> word[2:1] '' 索引可以是负数,计数从右边开始,例如: >>> word[-1] # The last character 'A' >>> word[-2] # The last-but-one character 'p' >>> word[-2:] # The last two characters 'pA' >>> word[:-2] # All but the last two characters 'Hel' 不过-0还是0,所以它不是从右边计数的! >>> word[-0] # (since -0 equals 0) 'H' 越界的负切片索引会被截断,不过不要尝试在前元素索引(非切片的)中这样做: >>> word[-100:] 'HelpA' >>> word[-10] # error Traceback (most recent call last): File "", line 1, in ? IndexError: string index out of range 理解切片的最好方式是把索引视为两个字符之间的点,第一个字符的左边是0,字符串中第n个字符的右边是索 引n,例如: +---+---+---+---+---+ | H | e | l | p | A | +---+---+---+---+---+ 0 1 2 3 4 5 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] -5 -4 -3 -2 -1 第一行是字符串中给定的0到5各个索引的位置,第二行是对应的负索引。从i到j的切片由这两个标志之间的字 符组成。 对于非负索引,切片长度就是两索引的差。例如,word[1:3]的长度是2。 内置函数 len() 返回字符串长度: >>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34 3.1.3 Unicode 字符串 从Python2.0开始,程序员们可以使用一种新的数据类型来存储文本数据:Unicode 对象。它可以用于存储多 种Unicode数据(请参阅 http://www.unicode.org/ ),并且,通过必要时的自动转换,它可以与现有的字符串 对象良好的结合。 Unicode针对现代和旧式的文本中所有的字符提供了一个序列。 以前,字符只能使用256个序号,文本通常通过 绑定代码页来与字符映射。这很容易导致混乱,特别是软件的国际化(internationalization--通常写 做“i18n”--“i”+18 characters +“n”)。Unicode通过为所有字符定义一个统一的代码页解决了这个问 题。 Python中定义一个Unicode字符串和定义一个普通字符串一样简单: >>> u'Hello World !' u'Hello World !' 引号前小写的“u”表示这里创建的是一个Unicode字符串。如果你想加入一个特殊字符,可以使用Python的 Unicode-Escape 编码。如下例所示: >>> u'Hello\u0020World !' u'Hello World !' 被替换的 \u0020 标识表示在给定位置插入编码值为 0x0020 的 Unicode字符(空格符)。 其它字符也会被直接解释成对应的Unicode码。如果你有一个在西方国家常用的Latin-1编码字符串,你可以发 现Unicode字符集的前256个字符与Lation-1的对应字符编码完全相同。 另外,有一种与普通字符串相同的行模式。想要使用Python的Raw-Unicode-Escape 编码,你需要在字符串的引 号前加上 ur 前缀。如果在小写“u”前可能有不止一个反斜杠,它只会把那些单独的 \uXXXX 转化为Unicode字 符。 >>> ur'Hello\u0020World !' u'Hello World !' >>> ur'Hello\\u0020World !' u'Hello\\\\u0020World !' 行模式在你需要输入很多个反斜杠时很有用,可能会用于正规表达式。 作为这些编码标准的一部分,Python提供了一个完备的方法集用于从已知的编码集创建Unicode字符串。 内置函数unicode() 提供了访问(编码和解码)所有已注册的Unicode编码的方法。它能转换众所周知的 Latin-1, 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] ASCII, UTF-8, 和 UTF-16。后面的两个可变长编码字符集用一个或多个byte存储Unicode字符。 默认的字符集 是 ASCII ,它只处理0到127的编码,拒绝其它的字符并返回一个错误。当一个Unicode字符串被打印、写入文 件或通过str()转化时,它们被替换为默认的编码。 >>> u"abc" u'abc' >>> str(u"abc") 'abc' >>> u"äöü" u'\xe4\xf6\xfc' >>> str(u"äöü") Traceback (most recent call last): File "", line 1, in ? UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) 要把一个Unicode字符串用指定的字符集转化成8位字符串,可以使用Unicode对象提供的encode()方法,它有一 个参数用以指定编码名称。编码名称小写。 >>> u"äöü".encode('utf-8') '\xc3\xa4\xc3\xb6\xc3\xbc' 如果你有一个特定编码的字符串,想要把它转为Unicode字符集,,可以使用uncode()函数,它以编码名做为第 二个参数。 >>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8') u'\xe4\xf6\xfc' 3.1.4 链表 Python 已经有了几个复合数据类型,用于组织其它的值。最通用的是链表,它写为中括之间用逗号分隔的一列 值(子项),链表的子项不一定是同一类型的值。 >>> a = ['spam', 'eggs', 100, 1234] >>> a ['spam', 'eggs', 100, 1234] 像字符串一样,链表也以零开始,可以被切片,联接,等等: >>> a[0] 'spam' >>> a[3] 1234 >>> a[-2] 100 >>> a[1:-1] ['eggs', 100] >>> a[:2] + ['bacon', 2*2] ['spam', 'eggs', 'bacon', 4] >>> 3*a[:3] + ['Boe!'] ['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!'] 与不变的字符串不同,链表可以改变每个独立元素的值: >>> a ['spam', 'eggs', 100, 1234] >>> a[2] = a[2] + 23 >>> a ['spam', 'eggs', 123, 1234] 可以进行切片操作,甚至还可以改变链表的大小: >>> # Replace some items: 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] ... a[0:2] = [1, 12] >>> a [1, 12, 123, 1234] >>> # Remove some: ... a[0:2] = [] >>> a [123, 1234] >>> # Insert some: ... a[1:1] = ['bletch', 'xyzzy'] >>> a [123, 'bletch', 'xyzzy', 1234] >>> a[:0] = a # Insert (a copy of) itself at the beginning >>> a [123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234] 内置函数len()也同样可以用于链表: >>> len(a) 8 它也可以嵌套链表(在链表中创建其它链表),例如: >>> q = [2, 3] >>> p = [1, q, 4] >>> len(p) 3 >>> p[1] [2, 3] >>> p[1][0] 2 >>> p[1].append('xtra') # See section 5.1 >>> p [1, [2, 3, 'xtra'], 4] >>> q [2, 3, 'xtra'] 注意最后一个例子,p[1]和q实际上指向同一个对象!我们在后面会讲到对象语法。 3.2 开始编程 当然,我们可以用Python做比2加2更复杂的事。例如,我们可以用以下的方法输出菲波那契(Fibonacci)序列 的子序列: >>> # Fibonacci series: ... # the sum of two elements defines the next ... a, b = 0, 1 >>> while b < 10: ... print b ... a, b = b, a+b ... 1 1 2 3 5 8 示例中介绍了一些新功能: 第一行包括了复合参数:变量a和b同时被赋值为0和1。最后一行又一次使用了这种技术,证明了在赋值 之前表达式右边先进行了运算。右边的表达式从左到右运算。 while循环运行在条件为真时执行。在Python中,类似于C任何非零值为真,零为假。 这个条件也可以用 于字符串或链表,事实上于对任何序列类型,长度非零时为真,空序列为假。示例所用的是一个简单的 3. 初步认识Python file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node5.html[09-5-21 ••08:01:11] 比较。标准的比较运算符写法和C相同: < (小于),> (大于),== (等于),<= (小于等 于),>=(大于等于)和!= (不等于)。 循环体是缩进的:缩进是Python对语句分组的方法。 Python仍没有提供一个智能编辑功能所以你要在每 一个缩进行输入一个tab或(一个或多个)空格。 实际上你可能会准备更为复杂的文本编辑器来编写你 的Python程序,大多数文本编辑器都提供了自动缩进功能。交互式的输入一个复杂语句时,需要用一个 空行表示完成(因为解释器没办法猜出你什么时候输入最后一行)。需要注意的是每一行都要有相同的 空字符来标识这是同一个语句块。 print语句打印给定表达式的值。它与你仅仅输入你需要的表达式(就像前面的计算器示例)不同,它可 以同时输出多个表达式。字符串输出时没有引号,各项之间用一个空格分开,你可以很容易区分它们, 如下所示: >>> i = 256*256 >>> print 'The value of i is', i The value of i is 65536 print语句末尾的逗号避免了输出中的换行: >>> a, b = 0, 1 >>> while b < 1000: ... print b, ... a, b = b, a+b ... 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 需要注意的是,如果最后一行仍没有写完,解释器会在它打印下一个命令时插入一个新行。 Python 手册 向前:2. 使用Python解释器 向上:Python 手册 向后: 4. 深入流程控制 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] Python中文社区 Python 指南 向前:3. 初步认识 Python 向上:Python 指南 向后:5. 数据结构 本节目录 4.1 if 语句 4.2 for 语句 4.3 range() 函数 4.4 break 和 continue 语句,以及 Loops 中的 else 子句 4.5 pass 语句 4.6 定义函数 4.7 深入函数定义 4.7.1 参数默认值 4.7.2 参数关键字 4.7.3 可变参数表 4.7.4 Lambda 形式 4.7.5 文档字符串 4. 其它流程控制工具 除了前面介绍的 while 语句,Python 还从别的语言中借鉴了一些流程控制功能,并有所改变。 4.1 if 语句 也许最有句的语句类型是 if 语句。例如: >>> x = int(raw_input("Please enter an integer: ")) >>> if x < 0: 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ... 可能会有 0 或很多个 elif 部分,else 是可选的。关键字“elif ” 是“ else if ”的缩写,这个可以有效避免过深的 缩进。if ... elif ... elif ... 序列用于替代其它语言中的 switch 或 case 语句。 4.2 for 语句 Python中的for 语句和你在 C 或 Pascal 中使用的略有不同。 通常的循环可能会依据一个等差数值步进过程 (如Pascal)或由用户来定义迭代步骤和中止条件(如C),Python 的 for 语句依据任意序列(链表或字符 串)中的子项,按它们在序列中的顺序来进行迭代。例如(没有暗指): >>> # Measure some strings: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12 在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改 你迭代的序列(例如,复制选择项),你可以迭代它的复本。通常使用切片标识就可以很方便的做到这一点: >>> for x in a[:]: # make a slice copy of the entire list ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate'] 4.3 range() 函数 如果你需要一个数值序列,内置函数range()可能会很有用,它生成一个等差级数链表。 >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] range(10)生成了一个包含10个值的链表,它准确的用链表的索引值填充了这个长度为10的列表,所生成的链表 中不包括范围中的结束值。也可以让range操作从另一个数值开始,或者可以指定一个不同的步进值(甚至是负 数,有时这也被称为“步长”): >>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70] 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] 需要迭代链表索引的话,如下所示结合使用range()和len(): >>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb 4.4 break 和 continue 语句, 以及循环中的 else 子句 break语句和C中的类似,用于跳出最近的一级for或while循环。 continue 语句是从C中借鉴来的,它表示循环继续执行下一次迭代。 循环可以有一个else子句;它在循环迭代完整个列表(对于for)或执行条件为false(对于while)时执行,但 循环被break中止的情况下不会执行。以下搜索素数的示例程序演示了这个子句: >>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', x, '*', n/x ... break ... else: ... # loop fell through without finding a factor ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3 4.5 pass 语句 pass 语句什么也不做。它用于那些语法上必须要有什么语句,但程序上什么也不要做的场合,例如: >>> while True: ... pass # Busy-wait for keyboard interrupt ... 4.6 定义函数 我们可以编写一个函数来生成有给定上界的菲波那契数列: >>> def fib(n): # write Fibonacci series up to n 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Now call the function we just defined: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 关键字def 引入了一个函数定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开 始,必须是缩进的。函数体的第一行可以是一个字符串值,这个字符串是该函数的 文档字符串,也可称 作docstring。 有些文档字符串工具可以在线处理或打印文档,或让用户交互的浏览代码;在你的代码中加入文档字符串是一 个好的作法,应该养成习惯。 调用函数时会为局部变量引入一个新的符号表。所有的局部变量都存储在这个局部符号表中。引用参数时,会 先从局部符号表中查找,然后是全局符号表,然后是内置命名表。因此,全局参数虽然可以被引用,但它们不 能在函数中直接赋值(除非它们用global语句命名)。 函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是传值调用(这里的值总是一个对象引用, 而不是该对象的值)。4.1 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。 函数定义在当前符号表中引入函数名。作为用户定义函数,函数名有一个为解释器认可的类型值。这个值可以 赋给其它命名,使其能句做为一个函数来使用。这就像一个重命名机制: >>> fib >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89 你可能认为fib不是一个函数(function),而是一个过程(procedure)。Python和C一样,过程只是一个没有返 回值的函数。实际上,从技术上讲,过程也有一个返回值,虽然是一个不讨人喜欢的。这个值被称为 None (这是一个内置命名)。如果一个值只是None的话,通常解释器不会写一个None出来,如果你真想要看它的 话,可以这样做: >>> print fib(0) None 以下示列演示了如何从函数中返回一个包含菲波那契数列的数值链表,而不是打印它: >>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while b < n: ... result.append(b) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] 和以前一样,这个例子演示了一些新的Python功能: return语句从函数中返回一个值,不带表达式的return返回None。过程结束后也会返回None。 语句result.append(b)称为链表对象result的一个方法(method)。方法是一个“属于”某个对象的函数,它 被命名为obj.methodename,这里的obj是某个对象(可能是一个表达式),methodename是某个在该对象 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] 类型定义中的方法的命名。 不同的类型定义不同的方法。不同类型可能有同样名字的方法,但不会混 淆。(当你定义自己的对象类型和方法时,可能会出现这种情况,本指南后面的章节会介绍如何使 用类)。示例中演示的append()方法由链表对象定义,它向链表中加入一个新元素。在示例中它等同 于"result = result + [b]",不过效率更高。 4.7 深入函数定义 有时需要定义参数个数可变的函数。有三个方法可以做到,我们可以组合使用它们。 4.7.1 参数默认值 最有用的形式是给一个或多个参数指定默认值。这样创建的函数可以在调用时使用更少的参数。 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return 1 if ok in ('n', 'no', 'nop', 'nope'): return 0 retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint 这个函数还可以用以下的方式调用:ask_ok('Do you really want to quit?'),或者像这样:ask_ok('OK to overwrite the file?', 2)。 默认值在函数定义段被解析,如下所示: i = 5 def f(arg=i): print arg i = 6 f() will print 5. 重要警告:默认值只会解析一次。当默认值是一个可变对象,诸如链表、字典或大部分类实例时,会产生一些 差异。例如,以下函数在后继的调用中会积累它的参数值: def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3) 这会打印出: [1] [1, 2] [1, 2, 3] 如果你不想在不同的函数调用之间共享参数默认值,可以如下面的实例一样编写函数: 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] def f(a, L=None): if L is None: L = [] L.append(a) return L 4.7.2 参数关键字 函数可以通过参数关键字的形式来调用,形如“keyword = value”。例如,以下的函数: def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "Volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!" 可以用以下的任一方法调用: parrot(1000) parrot(action = 'VOOOOOM', voltage = 1000000) parrot('a thousand', state = 'pushing up the daisies') parrot('a million', 'bereft of life', 'jump') 不过以下几种调用是无效的: parrot() # required argument missing(缺少必要参数) parrot(voltage=5.0, 'dead') # non-keyword argument following keyword(在关键字后面有非关键字参数) parrot(110, voltage=220) # duplicate value for argument(对参数进行了重复赋值) parrot(actor='John Cleese') # unknown keyword(未知关键字) 通常,参数列表中的每一个关键字都必须来自于形式参数,每个参数都有对应的关键字。形式参数有没有默认 值并不重要。实际参数不能一次赋多个值--形式参数不能在同一次调用中同时使用位置和关键字绑定值。这 里有一个例子演示了在这种约束下所出现的失败情况: >>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File "", line 1, in ? TypeError: function() got multiple values for keyword argument 'a' 引入一个形如 **name 的参数时,它接收一个字典,该字典包含了所有未出现在形式参数列表中的关键字参 数。这里可能还会组合使用一个形如 *name 的形式参数,它接收一个拓扑(下一节中会详细介绍),包含了所 有没有出现在形式参数列表中的参数值。(*name 必须在 **name 之前出现) 例如,我们这样定义一个函数: def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, '?' print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print '-'*40 keys = keywords.keys() keys.sort() for kw in keys: print kw, ':', keywords[kw] 它可以像这样调用: cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese', shopkeeper='Michael Palin', sketch='Cheese Shop Sketch') 当然它会按如下内容打印: 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] -- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch 注意sort()方法在关键字字典内容打印前被调用,否则的话,打印参数时的顺序是未定义的。 4.7.3 可变参数表 最后,一个最不常用的选择是可以让函数调用可变个数的参数。这些参数被包装进一个拓扑。在这些可变个数 的参数之前,可以有零到多个普通的参数: def fprintf(file, format, *args): file.write(format % args) 4.7.4 Lambda 形式 出于适当的需要,有几种通常在功能性语言和Lisp中出现的功能加入到了Python。通过lambda关键字,可以创 建很小的匿名函数。这里有一个函数返回它的两个参数的和:“lambda a, b: a+b”。 Lambda 形式可以用于任何 需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个 语法技巧。类似于嵌套函数定义,lambda形式可以从包含范围内引用变量: >>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43 4.7.5 文档字符串 这里介绍文档字符串的概念和格式。 第一行应该是关于对象用途的简介。简短起见,不用明确的陈述对象名或类型,因为它们可以从别的途径了解 到(除非这个名字碰巧就是描述这个函数操作的动词)。这一行应该以大写字母开头,以句号结尾。 如果文档字符串有多行,第二行应该空出来,与接下来的详细描述明确分隔。接下来的文档应该有一或多段描 述对象的调用约定、边界效应等。 Python的解释器不会从多行的文档字符串中去除缩进,所以必要的时候应当自己清除缩进。这符合通常的习 惯。第一行之后的第一个非空行决定了整个文档的缩进格式。(我们不用第一行是因为它通常紧靠着起始的引 号,缩进格式显示的不清楚。)留白“相当于”是字符串的起始缩进。 每一行都不应该有缩进,如果有缩进的 话,所有的留白都应该清除掉。相当于留白就是验证后的制表符扩展(通常是8个空格)。(这一段译得不 通,有疑问的读者请参见原文--译者) 4.深入流程控制 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node6.html[09-5-21 ••08:01:16] 以下是一个多行文档字符串的示例: >>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print my_function.__doc__ Do nothing, but document it. No, really, it doesn't do anything. 脚注 ... 对象)。4.1 实际上,说是调用对象引用更合适,因为如果传入一个可变对象,调用者可以得到被调用者产生的任何 改变(如链表中插入了子项)。 Python 指南 向前:3. 初步认识 Python 向上:Python 指南 向后:5. 数据结构 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] Python中文社区 Python指南 向前: 4. 深入流程控制 向上: Python 指南 向后: 6. 模块 子目录 5.1 深入链表 5.1.1 把链表当作堆栈使用 5.1.2 把链表当作队列使用 5.1.3 函数化编程工具 5.1.4 链表推导式 5.2 del 语句 5.3 元组(Tuples) 和 序列(Sequences) 5.4 字典(Dictionaries) 5.5 循环技巧 5.6 深入条件控制 5.7 比较序列(Sequences)和其它类型 5. 数据结构 本章节深入讲述一些你已经学习过的东西,并且还加入了新的内容。 5.1 深入链表 链表类型有很多方法,这里是链表类型的所有方法: append(x) 把一个元素添加到链表的结尾,相当于 a[len(a):] = [x]。 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] extend(L) 通过添加指定链表的所有元素来扩充链表,相当于 a[len(a):] = L 。 insert(i, x) 在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会 插入到整个链表之前,而 a.insert(len(a), x) 相当于 a.append(x)。 remove(x) 删除链表中值为x的第一个元素。如果没有这样的元素,就会返回一个错误。 pop([i]) 从链表的指定位置删除元素,并将其返回。如果没有指定索引,a.pop() 返回最后一个元素。元素随即从 链表中被删除。(方法中i两边的方括号表示这个参数是可选的,而不是要求你输入一对方括号,你会经 常在Python 库参考手册中遇到这样的标记。) index(x) 返回链表中第一个值为x的元素的索引。如果没有匹配的元素就会返回一个错误。 count(x) 返回x在链表中出现的次数。 sort() 对链表中的元素进行适当的排序。 reverse() 倒排链表中的元素。 下面这个示例演示了链表的大部分方法: >>> a = [66.6, 333, 333, 1, 1234.5] >>> print a.count(333), a.count(66.6), a.count('x') 2 1 0 >>> a.insert(2, -1) >>> a.append(333) >>> a [66.6, 333, -1, 333, 1, 1234.5, 333] >>> a.index(333) 1 >>> a.remove(333) >>> a [66.6, -1, 333, 1, 1234.5, 333] >>> a.reverse() >>> a [333, 1234.5, 1, 333, -1, 66.6] >>> a.sort() >>> a [-1, 1, 66.6, 333, 333, 1234.5] 5.1.1 把链表当作堆栈使用 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] 链表方法使得链表可以很方便的做为一个堆栈来使用,堆栈是这样的数据结构,最先进入的元素最后一个被释 放(后进先出)。用 append() 方法可以把一个元素添加到堆栈顶。用不指定索引的 pop() 方法可以把一个元素 从堆栈顶释放出来。例如: >>> stack = [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> stack [3, 4, 5, 6, 7] >>> stack.pop() 7 >>> stack [3, 4, 5, 6] >>> stack.pop() 6 >>> stack.pop() 5 >>> stack [3, 4] 5.1.2 把链表当作队列使用 你也可以把链表当做队列使用,队列是这样的数据结构,最先进入的元素最先释放(先进先出)。使用 append()方法可以把元素添加到队列最后,以0为参数调用 pop() 方法可以把最先进入的元素释放出来。例如: >>> queue = ["Eric", "John", "Michael"] >>> queue.append("Terry") # Terry arrives >>> queue.append("Graham") # Graham arrives >>> queue.pop(0) 'Eric' >>> queue.pop(0) 'John' >>> queue ['Michael', 'Terry', 'Graham'] 5.1.3 函数化编程工具 对于链表来讲,有三个内置函数非常有用:filter(), map(), 和 reduce()。 “filter(function, sequence)” 返回一个序列(sequence),包括了给定序列中所有调用function(item)后返回值 为true的元素。(如果可能的话,会返回相同的类型)。例如,以下程序可以计算部分素数: >>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23] “map(function, sequence)” 为每一个元素依次调用 function(item) 并将返回值组成一个链表返回。例如,以下程 序计算立方: >>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] 可以传入多个序列,函数也必须要有对应数量的参数,执行时会依次用各序列上对应的元素来调用函数(如果 某些序列比其它的短,就用None来代替)。如果把None做为一个函数传入,则直接返回参数做为替代。 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] 组合这两种情况,我们会发现“map(None, list1, list2)”是把一对序列变成元素对序列的便捷方式。例如: >>> seq = range(8) >>> def square(x): return x*x ... >>> map(None, seq, map(square, seq)) [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)] "reduce(func, sequence)" 返回一个单值,它是这样构造的:首先以序列的前两个元素调用函数,再以返回值 和第三个参数调用,依次执行下去。例如,以下程序计算1到10的整数之和: >>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55 如果序列中只有一个元素,就返回它,如果序列是空的,就抛出一个异常。 可以传入第三个参数做为初始值。如果序列是空的,就返回初始值,否则函数会先接收初始值和序列的第一个 元素,然后是返回值和下一个元素,依此类推。例如: >>> def sum(seq): ... def add(x,y): return x+y ... return reduce(add, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0 不要像示例中这样定义 sum():因为合计数值是一个通用的需求,在新的2.3版中,提供了内置的 sum(sequence) 函数。 5.1.4 链表推导式 链表推导式提供了一个创建链表的简单途径,无需使用 map(), filter() 以及 lambda。 返回链表的定义通常 要比创建这些链表更清晰。每一个链表推导式包括在一个for语句之后的表达式,零或多个for或if语句。返回值 是由for或if子句之后的表达式得到的元素组成的链表。如果想要得到一个元组,必须要加上括号。 >>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] >>> [weapon.strip() for weapon in freshfruit] ['banana', 'loganberry', 'passion fruit'] >>> vec = [2, 4, 6] >>> [3*x for x in vec] [6, 12, 18] >>> [3*x for x in vec if x > 3] [12, 18] >>> [3*x for x in vec if x < 2] [] >>> [[x,x**2] for x in vec] [[2, 4], [4, 16], [6, 36]] >>> [x, x**2 for x in vec] # error - parens required for tuples File "", line 1, in ? [x, x**2 for x in vec] ^ SyntaxError: invalid syntax >>> [(x, x**2) for x in vec] [(2, 4), (4, 16), (6, 36)] >>> vec1 = [2, 4, 6] >>> vec2 = [4, 3, -9] >>> [x*y for x in vec1 for y in vec2] [8, 6, -18, 16, 12, -36, 24, 18, -54] >>> [x+y for x in vec1 for y in vec2] [6, 5, -7, 8, 7, -5, 10, 9, -3] >>> [vec1[i]*vec2[i] for i in range(len(vec1))] [8, 12, -54] 为使链表推导式匹配for循环的行为,可以在推导之外保留循环变量: 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] >>> x = 100 # this gets overwritten >>> [x**3 for x in range(5)] [0, 1, 8, 27, 64] >>> x # the final value for range(5) 4 5.2 del 语句 有一个方法可从链表中删除指定索引的元素:del语句。这个方法也可以从链表中删除切片(之前我们是把一个 空链表赋给切片)。例如: >>> a = [-1, 1, 66.6, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.6, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.6, 1234.5] del 也可以用于删除整个变量: >>> del a 此后再引用这个名字会发生错误(至少要到给它赋另一个值为止)。后面我们还会发现del的其它用法。 5.3 元组(Tuples) 和序列(Sequences ) 我们知道链表和字符串有很多通用的属性,例如索引和切片操作。它们是序列类型中的两种。因为Python是一 个在不停进化的语言,也可以加入其它的序列类型,这里有另一种标准序列类型:元组。 一个元组由数个逗号分隔的值组成,例如: >>> t = 12345, 54321, 'hello!' >>> t[0] 12345 >>> t (12345, 54321, 'hello!') >>> # Tuples may be nested: ... u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) 如你所见,元组在输出时总是有括号的,以便于正确表达嵌套结构。在输入时可能有或没有括号都可以,不过 经常括号都是必须的(如果元组是一个更大的表达式的一部分)。 元组有很多用途。例如(x, y)坐标点,数据库中的员工记录等等。元组就像字符串,不可改变:不能给元组 的一个独立的元素赋值(尽管你可以通过联接和切片来模仿)。也可以通过包含可变对象来创建元组,例如链 表。 一个特殊的问题是构造包含零个或一个元素的元组:为了适应这种情况,语法上有一些额外的改变。一对空的 括号可以创建空元组;要创建一个单元素元组可以在值后面跟一个逗号(在括号中放入一个单值是不够的)。 丑陋,但是有效。例如: 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] >>> empty = () >>> singleton = 'hello', # <-- note trailing comma >>> len(empty) 0 >>> len(singleton) 1 >>> singleton ('hello',) 语句 t = 12345, 54321, 'hello!' 是元组封装(sequence packing)的一个例子:值 12345, 54321 和 'hello!' 被封装进元组。其逆操作可能是这样: >>> x, y, z = t 这个调用被称为序列拆封非常合适。序列拆封要求左侧的变量数目与序列的元素个数相同。要注意的是可变参 数(multiple assignment )其实只是元组封装和序列拆封的一个结合! 这里有一点不对称:封装多重参数通常会创建一个元组,而拆封操作可以作用于任何序列。 5.4 字典(Dictionaries) 另一个非常有用的Python内建数据类型是字典(Dictionaries)。字典在某些语言中可能称为“联合内 存”(``associative memories'')或“联合数组”(``associative arrays'')。序列是以连续的整数为索引,与此不 同的是,字典以关键字为索引,关键字可以是任意不可变类型,通常用字符串或数值。如果元组中只包含字符 串和数字,它可以做为关键字,如果它直接或间接的包含了可变对象,就不能当做关键字。不能用链表做关键 字,因为链表可以用它们的 append() 和 extend() 方法,或者用切片、或者通过检索变量来即时改变。 理解字典的最佳方式是把它看做无序的关键字:值对( key:value pairs )集合,关键字必须是互不相同的(在 同一个字典之内)。一对大括号创建一个空的字典:{}。初始化链表时,在大括号内放置一组逗号分隔的关键字:值对, 这也是字典输出的方式。 字典的主要操作是依据关键字来存储和析取值。也可以用del来删除关键字:值对。如果你用一个已经存在的关 键字存储值,以前为该关键字分配的值就会被遗忘。试图析取从一个不存在的关键字中读取值会导致错误。 字典的keys() 方法返回由所有关键字组成的链表,该链表的顺序不定(如果你需要它有序,只能调用关键字链表 的sort()方法)。使用字典的 has_key() 方法可以检查字典中是否存在某一关键字。 这是一个关于字典应用的小示例: >>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel {'sape': 4139, 'guido': 4127, 'jack': 4098} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel {'guido': 4127, 'irv': 4127, 'jack': 4098} >>> tel.keys() ['guido', 'irv', 'jack'] >>> tel.has_key('guido') True 链表中存储关键字-值对元组的话,字典可以从中直接构造。关键字-值对来自一个模式时,可以用链表推导式 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] 简单的表达关键字-值链表。 >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127} >>> dict([(x, x**2) for x in vec]) # use a list comprehension {2: 4, 4: 16, 6: 36} 5.5 循环技巧 在字典中循环时,关键字和对应的值可以使用 items() 方法同时解读出来。 >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.items(): ... print k, v ... gallahad the pure robin the brave 在序列中循环时,索引位置和对应值可以使用 enumerate() 函数同时得到。 >>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe 同时循环两个或更多的序列,可以使用 zip() 整体解读。 >>> questions = ['name', 'quest', 'favorite color'] >>> answers = ['lancelot', 'the holy grail', 'blue'] >>> for q, a in zip(questions, answers): ... print 'What is your %s? It is %s.' % (q, a) ... What is your name? It is lancelot. What is your quest? It is the holy grail. What is your favorite color? It is blue. 5.6 深入条件控制 用于while和if语句的条件包括了比较之外的操作符。 in和not比较操作符审核值是否在一个区间之内。操作符is和is not比较两个对象是否相同; 这只和诸如链表这 样的可变对象有关。所有的比较操作符具有相同的优先级,低于所有的数值操作。 比较操作可以传递。例如 a < b == c 审核是否a小于b并b等于c。 比较操作可以通过逻辑操作符and和or组合,比较的结果可以用not来取反义。这些操作符的优先级又低于比较 操作符,在它们之中,not具有最高的优先级,or的优先组最低,所以A and not B or C 等于 (A and (not B)) or C。当然,表达式可以用期望的方式表示。 逻辑操作符and 和or 也称作短路操作符:它们的参数从左向右解析,一旦结果可以确定就停止。例如,如 果A和C为真而B为假,A and B and C 不会解析C。作用于一个普通的非逻辑值时,短路操作符的返回值通常是 5. 数据结构 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node7.html[09-5-21 ••08:01:21] 最后一个变量。 可以把比较或其它逻辑表达式的返回值赋给一个变量,例如: >>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim' 需要注意的是Python与C不同,内部表达式不能分配值。C 程序员经常对此抱怨,不过它避免了一类在C程序中 司空见惯的错误:想要在解析式中使==时误用了=操作符。 5.7 比较序列和其它类型 序列对象可以与相同类型的其它对象比较。 比较操作按字典序进行:首先比较前两个元素,如果不同,就决定 了比较的结果;如果相同,就比较后两个元素,依此类推,直到所有序列都完成比较。如果两个元素本身就是 同样类型的序列,就递归字典序比较。如果两个序列的所有子项都相等,就认为序列相等。如果一个序列是另 一个序列的初始子序列,较短的一个序列就小于另一个。字符串的字典序按照单字符的ASCII顺序。下面是同 类型序列之间比较的一些例子: (1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4) 需要注意的是不同类型的对象比较是合法的。输出结果是确定而非任意的:类型按它们的名字排序。因而,一 个链表(list)总是小于一个字符串(string),一个字符串(string)总是小于一个元组(tuple)等等。数值类 型比较时会统一它们的数据类型,所以0等于0.0,等等。5.1 注释 ... etc.5.1 不同类型对象的比较规则不依赖于此,它们有可能会在Python语言的后继版本中改变。 Python 指南 向前: 4. 深入流程控制 向上: Python 指南 向后: 6. 模块 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] Python中文社区 Python 指南 向前: 5. 数据结构 向上: Python 指南 向后: 7. 输入和输出 章节目录 6.1 深入模块 6.1.1 模块搜索路径 6.1.2 “编译”Python 文件 6.2 标准模块 6.3 dir() 函数 6.4 包 6.4.1 从包中导入全部信息(Importing * From a Package) 6.4.2 内置包(Intra-package)参考 6.4.3 多重路径中的包 6. 模块 如果你退出Python解释器重新进入,以前创建的一切定义(变量和函数)就全部丢失了。因此,如果你想写一 些长久保存的程序,最好使用一个文本编辑器来编写程序,把保存好的文件输入解释器。 我们称之为创建一 个脚本。程序变得更长一些了,你可能为了方便维护而把它分离成几个文件。你也可能想要在几个程序中都使 用一个常用的函数,但是不想把它的定义复制到每一个程序里。 为了支持这些需要,Python提供了一个方法可以从文件中获取定义,在脚本或者解释器的一个交互式实例中使 用。这样的文件被称为实例;模块中的定义可以导入到另一个模块或主模块中(在脚本执行时可以调用的变量 集位于最高级,并且处于计算器模式) 模块是包括Python定义和声明的文件。文件名就是模块名加上.py后缀。模块的模块名(做为一个字符串)可以 由全局变量__name__得到。例如,你可以用自己惯用的文件编辑器在当前目录下创建一个叫fibo.py的文件,录 入如下内容: # Fibonacci numbers module def fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print b, 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] a, b = b, a+b def fib2(n): # return Fibonacci series up to n result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result 现在进入Python解释器用如下命令导入这个模块: >>> import fibo 这样做不会直接把fibo中的函数导入当前的语义表;,它只是引入了模块名fibo。你可以通过模块名按如下方式 访问这个函数: >>> fibo.fib(1000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>> fibo.fib2(100) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> fibo.__name__ 'fibo' 如果你想要直接调用函数,通常可以给它赋一个本地名称: >>> fib = fibo.fib >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 6.1 深入模块 模块可以像函数定义一样包含执行语句。这些语句通常用于初始化模块。它们只在模块第一次导入时执行一 次。6.1 对应于定义模块中所有函数的全局语义表,每一个模块有自己的私有语义表。因此,模块作者可以在模块中使 用一些全局变量,不会因为与用户的全局变量冲突而引发错误。另一方面,如果你确定你需要这个,可以像引 用模块中的函数一样获取模块中的全局变量,形如:modname.itemname。 模块可以导入(import)其它模块。习惯上所有的import语句都放在模块(或脚本,等等)的开头,但这并不 是必须的。被导入的模块名入在本模块的全局语义表中。 import语句的一个变体直接从被导入的模块中导入命名到本模块的语义表中。例如: >>> from fibo import fib, fib2 >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 这样不会从局域语义表中导入模块名(例如,fibo没有定义)。 这里还有一个变体从模块定义中导入所有命名: >>> from fibo import * >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 这样可以导入所有除了以下划线(_)开头的命名。 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] 6.1.1 模块搜索路径 导入一个叫spam的模块时,解释器先在当前目录中搜索名为spam.py的文件,然后在环境变 量PYTHONPATH指琮的目录列表中搜索,然后是环境变量PATH中的路径列表。如果PYTHONPATH没有设 置,或者文件没有找到,接下来搜索安装目录,在UNIX中,通常是 .:/usr/local/lib/python。 实际上,解释器由sys.path变量指定的路径目录搜索模块,该变量初始化时默认包含了输入脚本(或者当前目 录),PATHPATH和安装目录。这样就允许Python程序(原文如此,programs;我猜想应该是“programer”, 程序员--译者)了解如何修改或替换模块搜索目录。需要注意的是由于这些目录中包含有搜索路径中运行的 脚本,所以这些脚本不应该和标准模块重名,否则在导入模块时Python会尝试把这些脚本当作模块来加载。这 通常会引发一个错误。请参见 6.2节“标准模块”以了解更多的信息。 6.1.2 “编译”Python文件 对于引用了大量标准模块的短程序,有一个提高启动速度有重要方法,如果在spam.py目录下存在一个名 为spam.pyc的文件,它会被视为spam模块的预“编译”(``byte-compiled'' ,二进制编译)版本。用于创 建spam.pyc的这一版spam.py的修改时间记录在spam.pyc文件中,如果两者不匹配,.pyc文件就被忽略。 通常你不需要为创建spam.pyc文件做任何工作。一旦spam.py成功编译,就会试图编译对应版本的spam.pyc。如 果有任何原因导致写入不成功,返回的spam.pyc文件就会视为无效,随后即被忽略。spam.pyc文件的内容是平 台独立的,所以Python模块目录可以在不同架构的机器之间共享。 部分高级技巧: 以-O参数调用Python解释器时,会生成优化代码并保存在.pyo文件中。通用的优化器没有太多帮助;它只 是删除了断言(assert)语句。使用-O参数,所有的代码都会被优化;.pyc文件被忽略,.py文件被编译为 优化代码。 向Python解释器传递两个 -O 参数(-OO)会执行完全优化的二进制优化编译,这偶尔会生成错误的程 序。当前,压缩的.pyo文件只是从二进制代码中删除了__doc__字符串。因为某些程序依赖于这些变量的 可用性,你应该只在确定无误的场合使用这一选项。 来自.pyc文件或.pyo文件中的程序不会比来自.py文件的运行更快;.pyc或.pyo文件只是在它们加载的时候 更快一些。 通过脚本名在命令行运行脚本时,不会为该脚本向创建.pyc或.pyo文件的二进制代码。当然,把脚本的主 要代码移进一个模块里,然后用一个小的解构脚本导入这个模块,就可以提高脚本的启动速度。也可以 直接在命令行中指定一个.pyc或乾.pyo文件。 对于同一个模块(这里指例程spam--译者),可以只有spam.pyc文件(或者spam.pyo,在使用 -O 参数 时)而没有spam.py文件。这样可以打包发布比较于逆向工程的Python代码库。 compileall模块 可以为指定目录中的所有模块创建.pyc文件(或者使用-O参数创建.pyo文件)。 6.2 标准模块 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] Python带有一个标准模块库,并发布有独立的文档,名为 Python 库参考手册 (此后称其为“库参考手 册”)。有一些模块内置于解释器之中,这些操作的访问接口不是语言内核的一部分,但是已经内置于解释器 了。这既是为了提高效率,也是为了给系统调用等操作系统原生访问提供接口。这类模块集合是一个依赖于底 层平台的配置选项。例如,amoeba模块只提供对Amoeba原生系统的支持。有一个具体的模块值得注意:sys , 这个模块内置于所有的Python解释器。变量 sys.ps1 和 sys.ps2 定义了主提示符和副助提示符字符串: >>> import sys >>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print 'Yuck!' Yuck! C> 这两个变量只在解释器的交互模式下有意义(此处原文为:These two variables are only defined if the interpreter is in interactive mode. )。 变量sys.path 是解释器模块搜索路径的字符串列表。它由环境变量PYTHONPATH初始化,如 果PYTHONPATH没有内定,就由内置的默认值初始化。你可以用标准和字符串操作修改它: >>> import sys >>> sys.path.append('/ufs/guido/lib/python') 6.3 dir() 函数 内置函数dir()用于按模块名搜索模块定义,它返回一个字符串类型的存储列表: >>> import fibo, sys >>> dir(fibo) ['__name__', 'fib', 'fib2'] >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'api_version', 'argv', 'builtin_module_names', 'byteorder', 'callstats', 'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags', 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'version', 'version_info', 'warnoptions'] 无参数调用时,dir()函数返回你当前定义的名称: >>> a = [1, 2, 3, 4, 5] >>> import fibo, sys >>> fib = fibo.fib >>> dir() ['__name__', 'a', 'fib', 'fibo', 'sys'] 应该该列表列出了所有类型的名称:变量,模块,函数,等等: dir()不会列出内置函数和变量名。如果你想列出这此内容,它们在标准模块__buildin__中定义: >>> import __builtin__ >>> dir(__builtin__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] 'Exception', 'False', 'FloatingPointError', 'IOError', 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeError', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__debug__', '__doc__', '__import__', '__name__', 'abs', 'apply', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'round', 'setattr', 'slice', 'staticmethod', 'str', 'string', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] 6.4 包 包通常是使用用“圆点模块名”的结构化模块命名空间。例如,名为A.B的模块表示了名为“A”的包中名 为“B”的子模块。正如同用模块来保存不同的模块架构可以避免全局变量之间的相互冲突,使用圆点模块名 保存像NunPy或Python Imaging Library之类的不同类库架构可以避免模块之间的命名冲突。 假设你现在想要设计一个模块集(一个“包”)来统一处理声音文件和声音数据。存在几种不同的声音格式 (通常由它们的扩展名来标识,例如:.wav,.aiff,.au),于是,为了在不同类型的文件格式之间转换,你需 要维护一个不断增长的包集合。 可能你还想要对声音数据做很多不同的操作(例如混音,添加回声,应用平衡 功能,创建一个人造效果),所以你要加入一个无限流模块来执行这些操作。你的包可能会是这个样子(通过 分级的文件体系来进行分组): Sound/ Top-level package __init__.py Initialize the sound package Formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... Effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py ... Filters/ Subpackage for filters __init__.py equalizer.py vocoder.py karaoke.py ... 导入模块时,Python通过sys.path中的目录列表来搜索存放包的子目录。 必须要有一个__init__.py 文件的存在,才能使Python视该目录为一个包;这是为了防止某些目录使用 了“string”这样的通用名而无意中在随后的模块搜索路径中覆盖了正确的模块。最简单的情况下,__init__.py 可以只是一个空文件,不过它也可能包含了包的初始化代码,或者设置了 __all__ 变量,后面会有相关介绍。 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] 包用户可以从包中导入合法的模块,例如: import Sound.Effects.echo 这样就导入了Sound.Effects.echo子模块。它必需通过完整的名称来引用。 Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4) 导入包时有一个可以选择的方式: from Sound.Effects import echo 这样就加载了echo子模块,并且使得它在没有包前缀的情况下也可以使用,所以它可以如下方式调用: echo.echofilter(input, output, delay=0.7, atten=4) 还有另一种变体用于直接导入函数或变量: from Sound.Effects.echo import echofilter 这样就又一次加载了echo子模块,但这样就可以直接调用它的 echofilter() 函数: echofilter(input, output, delay=0.7, atten=4) 需要注意的是使用 from package import item 方式导入包时,这个子项(item)既可以是包中的一个子模块 (或一个子包),也可以是包中定义的其它命名,像函数、类或变量。import 语句首先核对是否包中有这个子 项,如果没有,它假定这是一个模块,并尝试加载它。如果没有找到它,会引发一个 ImportError 异常。 相反,使用类似import item.subitem.subsubitem 这样的语法时,这些子项必须是包,最后的子项可以是包或模 块,但不能是前面子项中定义的类、函数或变量。 6.4.1 从包中导入全部信息(Importing * From a Package) 那么当用户写下from Sound.Effects import *时会发生什么事?理想中,总是希望在文件系统中找出包中所有的子模块,然 后导入它们。不幸的是,这个操作在Mac 和 Windows 平台上工作的并不太好,这些文件系统的文件大小写并不敏感! 在这些平台上没有什么方法可以确保一个叫ECHO.PY的文件应该导入为模块echo、Echo或ECHO。(例 如,Windows 95有一个讨厌的习惯,它会把所有的文件名都显示为首字母大写的风格。) DOS 8+3文件名限 制又给长文件名模块带来了另一个有趣的问题。 对于包的作者来说唯一的解决方案就是给提供一个明确的包索引。import语句按如下条件进行转换:执行from packae import * 时,如果包中的__init__.py代码定义了一个名为__all__的链表,就会按照链表中给出的模块名 进行导入。新版本的包发布时作者可以任意更新这个链表。如果包作者不想import * 的时候导入他们的包中所 有模块,那么也可能会决定不支持它(import *)。例如,Sounds/Effects/__init__.py 这个文件可能包括如下 代码: __all__ = ["echo", "surround", "reverse"] 这意味着 from Sound.Effects import * 语句会从Sound 包中导入以上三个已命名的子模块。 如果没有定义 __all__ ,from Sound.Effects import * 语句不会从Sound.Effects包中导入所有的子模 块。Effects 导入到当前的命名空间,只能确定的是导入了 Sound.Effects 包(可能会运行 __init__.py中的初 始化代码)以及包中定义的所有命名会随之导入。这样就从__init__.py中导入了每一个命名(以及明确导入的 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] 子模块)。同样也包括了前述的import语句从包中明确导入的子模块,考虑以下代码: import Sound.Effects.echo import Sound.Effects.surround from Sound.Effects import * 在这个例子中,echo和surround模块导入了当前的命名空间,这是因为执行from ... import语句时它们已经定义 在Sound.Effects包中了(定义了__all__时也会同样工作)。 需要注意的是习惯上不主张从一个包或模块中用import * 导入所有模块,因为这样的通常意味着可读性会很 差。然而,在交互会话中这样做可以减少输入,相对来说确定的模块被设计成只导出确定的模式中命名的那一 部分。 记住,from Package import specific_submodule没有错误!事实上,除非导入的模块需要使用其它包中的同 名子模块,否则这是受到推荐的写法。 6.4.2 内置包(Intra-package)参考 子模块之间经常需要互相引用。例如,surround 模块可能会引用echo 模块。事实上,这样的引用如此普遍, 以致于import语句会先搜索包内部,然后才是标准模块搜索路径。因此surround module 可以简单的调用import echo 或者 from echo import echofilter。如果没有在当前的包中发现要导入的模块,import语句会依据指定 名寻找一个顶级模块。 如果包中使用了子包结构(就像示例中的Sound包),不存在什么从邻近的包中引用子模块的便捷方法--必 须使用子包的全名。例 如,如果Sound.Filters.vocoder 包需要使用Sound.Effects 包中的echosa模块,它可以 使用from Sound.Effects import echo。 6.4.3 多重路径中的包 包支持一个另为特殊的变量, __path__。 在包的__init__.py文件代码执行之前,该变量初始化一个目录名列 表。该变量可以修改,它作用于包中的子包和模块的搜索功能。 这个功能可以用于扩展包中的模块集,不过它不常用。 Footnotes ... somewhere.6.1 事实上函数定义既是“声明”又是“可执行体”;执行体由函数在模块全局语义表中的命名导入。(In fact function definitions are also `statements' that are `executed'; the execution enters the function name in the module's global symbol table. ) Python 指南 向前: 5. 数据结构 向上: Python 指南 向后: 7. 输入和输出 Release 2.3, documentation updated on July 29, 2003. 6. 模块 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node8.html[09-5-21 ••08:01:25] See About this document... for information on suggesting changes. Python中文社区 7. 输入和输出 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node9.html[09-5-21 ••08:01:30] Python中文社区 Python 指南 向前: 6. 模块 向上: Python 指南 向后:8. 错语和异常 章节目录 7.1 设计输出格式 7.2 读写文件 7.2.1 文件对象(file object)方法 7.2.2 pickle 模块 7. 输入和输出 有几种方法可以表现程序的输出结果;数据可以用可读的结构打印,也可以写入文件供以后使用。本章将会讨 论几种可行的做法。 7.1 设计输出格式 我们有两种大相径庭的输出值方法:表达式语句和print语句。(第三种访求是使用文件对象的wite()方法,标 准文件输出可以参考sys.stdout。详细内容参见库参考手册。) 可能你经常想要对输出格式做一些比简单的打印空格分隔符更为复杂的控制。有两种方法可以格式化输出。第 一种是由你来控制整个字符串,使用字符切片和联接操作就可以创建出任何你想要的输出形式。标准模块 string 包括了一些操作,将字符串填充入给定列时,这些操作很有用。随后我们会讨论这部分内容。第二种方 法是使用 % 操作符,以某个字符串做为其左参数。 % 操作符将左参数解释为类似于 sprintf()风格的格式字符 串,并作用于右参数,从该操作中返回格式化的字符串。 当然,还有一个问题,如何将(不同的)值转化为字符串?很幸运,Python总是把任意值传入 repr() 或 str() 函 数,转为字符串。相对而言引号('')等价于repr(),不过不提倡这样用。 函数str() 用于将值转化为适于人阅读的形式,而 repr()转化为供解释器读取的形式(如果没有等价的语法,则会发 生SyntaxError 异常) 某对象没有适于人阅读的解释形式的话,str()会返回与repr()等同的值。很多类型,诸如数 值或链表、字典这样的结构,针对各函数都有着统一的解读方式。字符串和浮点数,有着独特的解读方式。 以下是一些示例: 7. 输入和输出 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node9.html[09-5-21 ••08:01:30] >>> s = 'Hello, world.' >>> str(s) 'Hello, world.' >>> repr(s) "'Hello, world.'" >>> str(0.1) '0.1' >>> repr(0.1) '0.10000000000000001' >>> x = 10 * 3.25 >>> y = 200 * 200 >>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...' >>> print s The value of x is 32.5, and y is 40000... >>> # The repr() of a string adds string quotes and backslashes: ... hello = 'hello, world\n' >>> hellos = repr(hello) >>> print hellos 'hello, world\n' >>> # The argument to repr() may be any Python object: ... repr((x, y, ('spam', 'eggs'))) "(32.5, 40000, ('spam', 'eggs'))" >>> # reverse quotes are convenient in interactive sessions: ... `x, y, ('spam', 'eggs')` "(32.5, 40000, ('spam', 'eggs'))" 以下两种方法可以输出平方和立方表: >>> import string >>> for x in range(1, 11): ... print string.rjust(repr(x), 2), string.rjust(repr(x*x), 3), ... # Note trailing comma on previous line ... print string.rjust(repr(x*x*x), 4) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 >>> for x in range(1,11): ... print '%2d %3d %4d' % (x, x*x, x*x*x) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 (需要注意的是使用print方法时每两列之间有一个空格:它总是在参数之间加一个空格。) 以上是一个string.rjust()函数的演示,这个函数把字符串输出到一列,并通过向左侧填充空格来使其右对齐。类 似的函数还有 string.ljust() 和 string.center()。这些函数只是输出新的字符串,并不改变什么。如果输出的字符串太长,它 们也不会截断它,而是原样输出,这会使你的输出格式变得混乱,不过总强过另一种选择(截断字符串),因为那样会产生错误的输出 值。(如果你确实需要截断它,可以使用切片操作,例如:"string.ljust(x, n)[0:n]"。) 还有一个函数,string.zfill()它用于向数值的字符串表达左侧填充0。该函数可以正确理解正负号: >>> import string >>> string.zfill('12', 5) '00012' >>> string.zfill('-3.14', 7) '-003.14' >>> string.zfill('3.14159265359', 5) '3.14159265359' 7. 输入和输出 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node9.html[09-5-21 ••08:01:30] 可以如下这样使用 % 操作符: >>> import math >>> print 'The value of PI is approximately %5.3f.' % math.pi The value of PI is approximately 3.142. 如果有超过一个的字符串要格式化为一体,就需要将它们传入一个元组做为右值,如下所示: >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} >>> for name, phone in table.items(): ... print '%-10s ==> %10d' % (name, phone) ... Jack ==> 4098 Dcab ==> 7678 Sjoerd ==> 4127 大多数类C的格式化操作都需要你传入适当的类型,不过如果你没有定义异常,也不会有什么从内核中主动的 弹出来。(however, if you don't you get an exception, not a core dump) 使用 %s 格式会更轻松些:如果对应的参 数不是字符串,它会通过内置的 str() 函数转化为字符串。Python支持用 * 作为一个隔离(整型的)参数来传 递宽度或精度。Python不支持C的 %n 和 %p 操作符。 如果可以逐点引用要格式化的变量名,就可以产生符合真实长度的格式化字符串,不会产生间隔。这一效果可 以通过使用 form %(name)结构来实现: >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} >>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table Jack: 4098; Sjoerd: 4127; Dcab: 8637678 这个技巧在与新的内置函数 vars() 组合使用时非常有用,该函数返回一个包含所有局部变量的字典。 7.2 读写文件 open() 返回一个文件对象 ,通常的用法需要两个参数:“open(filename, mode)”。 >>> f=open('/tmp/workfile', 'w') >>> print f 第一个参数是一个标识文件名的字符串。第二个参数是由有限的字母组成的字符串,描述了文件将会被如何使 用。可选的模式有:‘r',此选项使文件只读;‘w’,此选项使文件只写(对于同名文件,该操作使原有文 件被覆盖); ‘a’,此选项以追加方式打开文件;‘r+’,此选项以读写方式打开文件;如果没有指定,默 认为‘r’模式。 在Windows 和 Macintosh平台上,‘b’模式以二进制方式打开文件,所以可能会有类似 于‘rb’,‘wb’,‘r+b’等等模式组合。 Windows平台上文本文件与二进制文件是有区别的,读写文本文 件时,行尾会自动添加行结束符。 这种后台操作方式对文本文件没有什么问题,但是操作JPEG或EXE这样的 二进制文件时就会产生破坏。在操作这些文件时一定要记得以二进制模式打开。(需要注意的是Mactiontosh平 台上的文本模式依赖于其使用的底层C库)。 7.2.1 文件对象(file object)的方法 7. 输入和输出 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node9.html[09-5-21 ••08:01:30] 本节中的示例都默认文件对象f已经创建。 要读取文件内容,需要调用 f.read(size),该方法读取若干数量的数据并以字符串形式返回其内容,字符串长度 为数值size所指定的大小。如果没有指定size或者指定为负数,就会读取并返回整个文件。当文件大小为当前机 器内存两倍时,就会产生问题。正常情况下,会按size尽可能大的读取和返回数据。如果到了文件末 尾,f.read() 会返回一个空字符串("")。 >>> f.read() 'This is the entire file.\n' >>> f.read() '' f.readline() 从文件中读取单独一行,字符串结尾会自动加上一个换行符,只有当文件最后一行没有以换行符 结尾时,这一操作才会被忽略。这样返回值就不会有什么混淆不清,如果 if f.readline() 返回一个空字符串, 那就表示到达了文件末尾,如果是一个空行,就会描述为‘\n’,一个只包含换行符的字符串。 >>> f.readline() 'This is the first line of the file.\n' >>> f.readline() 'Second line of the file\n' >>> f.readline() '' f.readlines() 返回一个列表,其中包含了文件中所有的数据行。如果给定了 sizehint 参数,就会读入多于一行 的比特数,从中返回行列表。这个功能通常用于高效读取大型行文件,避免了将整个文件读入内存。这种操作 只返回完整的行。 >>> f.readlines() ['This is the first line of the file.\n', 'Second line of the file\n'] f.write(string) 将 string 的内容写入文件,返回None。 >>> f.write('This is a test\n') f.tell() 返回一个整数,代表文件对象在文件中的指针位置,该数值计量了自文件开头到指针处的比特数。需 要改变文件对象指针话话,使用“f.seek(offset, from_what)” 。指针在该操作中从指定的引用位置移动 offset 比特,引用位置由 from_what 参数指定。. from_what 值为0表示自文件起初处开始,1表示自当前文件指 针位置开始,2表示自文件末尾开始。 from_what 可以乎略,其默认值为零,此时从文件头开始。 >>> f=open('/tmp/workfile', 'r+') >>> f.write('0123456789abcdef') >>> f.seek(5) # Go to the 6th byte in the file >>> f.read(1) '5' >>> f.seek(-3, 2) # Go to the 3rd byte before the end >>> f.read(1) 'd' 文件使用完后,调用 f.close() 可以关闭文件,释放打开文件后占用的系统资源。调用 f.close()之后,再调 用文件对象会自动引发错误。 >>> f.close() >>> f.read() Traceback (most recent call last): File "", line 1, in ? ValueError: I/O operation on closed file 文件对象还有一些不太常用的附加方法,比如 isatty() 和 truncate() 在库参考手册中有文件对象的完整指 南。 7. 输入和输出 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node9.html[09-5-21 ••08:01:30] 7.2.2 pickle 模块 我们可以很容易的读写文件中的字符串。数值就要多费点儿周折,因为read() 方法只会返回字符串,应该将其 传入string.atoi()方法中,就可以将'123' 这样的字符转为相应的值。不过,当你需要保存更为复杂的数据类 型,例如链表、字典,类的实例,事情就会变得更复杂了。 好在用户不必要非得自己编写和调试保存复杂数据类型的代码。Python提供了一个名为 Pickle 的标准模块。这 是一个令人赞叹的模块,几乎可以把任何Python对象(甚至是一些Python代码块(form)!)表达为为字符 串,这一过程称之为封装 (pickling)。从字符串表达出重新构造对象称之为拆封(unpickling)。封装状态中 的对象可以存储在文件或对象中,也可以通过网络在远程的机器之间传输。 如果你有一个对象x,一个以写模式打开的文件对象f,封装对像的最简单的方法只需要一行代码: pickle.dump(x, f) 如果f是一个以读模式打开的文件对象,就可以重装拆封这个对象: x = pickle.load(f) (如果不想把封装的数据写入文件,这里还有一些其它的变化可用。完整的pickle文档请见库参考手册)。 pickle 是存储Python对象以供其它程序或其本身以后调用的标准方法。提供这一组技术的是一个持久化对象( persistent object )。因为 pickle 的用途很广泛,很多Python扩展的作者都非常注意类似矩阵这样的新数据类型 是否适合封装和拆封。 Python 指南 向前: 6. 模块 向上: Python 指南 向后:8. 错语和异常 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] Python中文社区 Python 指南 向前: 7. 输入和输出 向上: Python 指南 向后: 9. 类 子目录 8.1 语法错误 8.2 异常 8.3 处理异常 8.4 抛出异常 8.5 用户自定义异常 8.6 定义清理行为 8. 错误和异常 至今为止还没有进一步的谈论过错误信息,不过在你已经试验过的那些例子中,可能已经遇到过一 些。Python中(至少)有两种错误:语法错误和异常( syntax errors and exceptions)。 8.1 语法错误 语法错误,也称作解析错误,可能是学习Python的过程中最容易犯的: >>> while True print 'Hello world' File "", line 1, in ? while True print 'Hello world' ^ SyntaxError: invalid syntax 解析器会重复出错的行,并在行中最早发现的错误位置上显示一个小箭头。错误(至少是被检测到)就发生在 箭头指向的位置。示例中的错误表现在关键字print上,因为在它之前少了一个冒号(:)。同时也会显示文件名 和行号,这样你就可以知道错误来自哪个脚本,什么位置。 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] 8.2 异常 即使是在语法上完全正确的语句,尝试执行它的时候,也有可能会发生错误。在程序运行中检测出的错误称之 为异常,它通常不会导致致命的问题,你很快就会学到如何在Python程序中控制它们。大多数异常不会由程序 处理,而是显示一个错误信息: >>> 10 * (1/0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: integer division or modulo by zero >>> 4 + spam*3 Traceback (most recent call last): File "", line 1, in ? NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "", line 1, in ? TypeError: cannot concatenate 'str' and 'int' objects 错误信息的最后一行指出发生了什么错误。异常也有不同的类型,异常类型做为错误信息的一部分显示出来: 示例中的异常分别为零除错误( ZeroDivisionError ),命名错误( NameError)和类型错误( TypeError )。打印错误信息时,异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异 常就不一定了(尽管这是一个很有用的约定)。标准异常名是内置的标识(没有保留关键字)。 这一行后一部分是关于该异常类型的详细说明,这意味着它的内容依赖于异常类型。 错误信息的前半部分以堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行,然而,来自标准输入 的源码不会显示出来。 Python 库参考手册 列出了内置异常和它们的含义。 8.3 处理异常 通过编程可以处理指定的异常。以下的例子重复要求用户输入一个值,直到用户输入的是一个合法的整数为 止。不过这个程序允许用户中断程序(使用 Control-C 或者其它操作系统支持的方法)。需要注意的是用户发 出的中断会引发一个 KeyboardInterrupt 异常。 >>> while True: ... try: ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: ... print "Oops! That was no valid number. Try again..." ... try 语句按如下方式工作: 首先,执行 try 子句(在try 和 except关键字之间的部分)。 如果没有异常发生,except 子句 在try语句执行完毕后就被忽略了。 如果在try子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。如果异常匹配于except关键字 后面指定的异常类型,就执行对应的except子句,忽略try子句的其它部分。然后继续执行try语句之后的 代码。 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] 如果发生了一个异常,在except子句中没有与之匹配的分支,它就会传递到上一级try语句中。如果最终仍 找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。 一个try 语句可能包含多个 except 子句,分别指定处理不同的异常。至多只会有一个分支被执行。 异常处理程 序只会处理对应的try子句中发生的异常,在同一个try语句中,其他子句中发生的异常则不作处理。一 个except子句可以在括号中列出多个异常的名字,例如: ... except (RuntimeError, TypeError, NameError): ... pass 最后一个except子句可以省略异常名,把它当做一个通配项使用。一定要慎用这种方法,因为它很可能会屏蔽 掉真正的程序错误,使人无法发现!它也可以用于打印一行错误信息,然后重新抛出异常(可以使调用者更好 的处理异常)。 import string, sys try: f = open('myfile.txt') s = f.readline() i = int(string.strip(s)) except IOError, (errno, strerror): print "I/O error(%s): %s" % (errno, strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise try ... except 语句可以带有一个 else 子句, 该子句只能出现在所有except子句之后。当try语句没有抛出异常 时,需要执行一些代码,可以使用这个子句。例如: for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close() 使用 else 子句比在 try 子句中附加代码要好,因为这样可以避免 try ... except 意外的截获本来不属于它们保 护的那些代码抛出的异常。 发生异常时,可能会有一个附属值,作为异常的参数存在。这个参数是否存在、是什么类型,依赖于异常的类 型。 在异常名(列表)之后,也可以为 except 子句指定一个变量。这个变量绑定于一个异常实例,它存储在 instance.args 的参数中。为了方便起见,异常实例定义了 __getitem__ 和 __str__ ,这样就可以直接访问过 打印参数而不必引用 .args。 >>> try: ... raise Exception('spam', 'eggs') ... except Exception, inst: ... print type(inst) # the exception instance ... print inst.args # arguments stored in .args ... print inst # __str__ allows args to printed directly ... x, y = inst # __getitem__ allows args to be unpacked directly ... print 'x =', x ... print 'y =', y ... ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] 对于未处理的异常,如果它有一个参数,那做就会作为错误信息的最后一部分(“明细”)打印出来。 异常处理句柄不止可以处理直接发生在try子句中的异常,即使是其中(甚至是间接)调用的函数,发生了异 常,也一样可以处理。例如: >>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError, detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo 8.4 抛出异常 在发生了特定的异常时,程序员可以用 raise 语句强制抛出异常。例如: >>> raise NameError, 'HiThere' Traceback (most recent call last): File "", line 1, in ? NameError: HiThere 第一个参数指定了所抛出异常的名称,第二个指定了异常的参数。 如果你决定抛出一个异常而不处理它,raise 语句可以让你很简单的重新抛出该异常。 >>> try: ... raise NameError, 'HiThere' ... except NameError: ... print 'An exception flew by!' ... raise ... An exception flew by! Traceback (most recent call last): File "", line 2, in ? NameError: HiThere 8.5 用户自定义异常 在程序中可以通过创建新的异常类型来命名自己的异常。异常类通常应该直接或间接的从 Exception 类派生, 例如: >>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MyError(2*2) ... except MyError, e: ... print 'My exception occurred, value:', e.value ... My exception occurred, value: 4 >>> raise MyError, 'oops!' 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] Traceback (most recent call last): File "", line 1, in ? __main__.MyError: 'oops!' 异常类中可以定义任何其它类中可以定义的东西,但是通常为了保持简单,只在其中加入几个属性信息,以供 异常处理句柄提取。如果一个新创建的模块中需要抛出几种不同的错误时,一个通常的作法是为该模块定义一 个异常基类,然后针对不同的错误类型派生出对应的异常子类。 class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message 与标准异常相似,大多数异常的命名都以“Error”结尾。 很多标准模块中都定义了自己的异常,用以报告在他们所定义的函数中可能发生的错误。关于类的进一步信息 请参见第 9章,“类”。 8.6 定义清理行为 try 语句还有另一个可选的子句,目的在于定义在任何情况下都一定要执行的功能。例如: >>> try: ... raise KeyboardInterrupt ... finally: ... print 'Goodbye, world!' ... Goodbye, world! Traceback (most recent call last): File "", line 2, in ? KeyboardInterrupt 不管try子句中有没有发生异常, finally 子句都一定会被执行。如果发生异常,在finally子句执行完后它会被重 新抛出。 try 子句经由 break 或 return 退出也一样会执行finally 子句。 在finally 子句中的代码用于释放外部资源(例如文件或网络连接),不管这些资源是否已经成功利用。 8. 错误和异常 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node10.html[09-5-21 ••08:01:34] 在 try 语句中可以使用若干个 except 子句或一个 finally 子句,但两者不能共存。 Python 指南 向前: 7. 输入和输出 向上: Python 指南 向后: 9. 类 Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] Python中文社区 Python 指南 向前: 8. 错误和异常 向上: Python 指南 向后: 10. 接下来? 章节目录 9.1 有关术语的话题 9.2 Python 作用域和命名空间 9.3 初识类 9.3.1 类定义语法 9.3.2 类对象 9.3.3 实例对象 9.3.4 方法对象 9.4 一些说明 9.5 继承 9.5.1 多继承 9.6 私有变量 9.7 补充 9.8 异常也是类 9.9 迭代器 9.10 发生器 9. 类 Python在尽可能不增加新的语法和语义的情况下加入了类机制。这种机制是C++和Python's Modula-3的混 合。Python中的类没有在用户和定义之间建立一个绝对的屏障,而是依赖于用户自觉的不去“破坏定义”。然 而,类机制最重要的功能都完整的保留下来。类继承机制允许多继承,派生类可以覆盖(override)基类中的 任何方法,方法中可以调用基类中的同名方法。对象可以包含任意数量的私有成员。 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 用C++术语来讲,所有的类成员(包括数据成员)都是公有(public)的,所有的成员函数都是虚拟(virtual) 的。用Modula-3的术语来讲,在成员方法中没有什么简便的方式(shorthands)可以引用对象的成员:方法函 数在定义时需要以引用的对象做为第一个参数,以调用时则会隐式引用对象。这样就形成了语义上的引入和重 命名。( This provides semantics for importing and renaming. )但是,像C++而非Modula-3中那样,大多数带有 特殊语法的内置操作符(算法运算符、下标等)都可以针对类的需要重新定义。 9.1 有关术语的话题 由于没有什么关于类的通用术语,我从Smalltalk和C++中借用一些(我更希望用Modula-3的,因为它的面向对 象机制比C++更接近Python,不过我想没多少读者听说过它)。 我要提醒读者,这里有一个面向对象方面的术语陷阱,在Python中“对象”这个词不一定指类实例。Python中 并非所有的类型都是类:例如整型、链表这些内置数据类型就不是,甚至某些像文件这样的外部类型也不是, 这一点类似于C++和Modula-3,而不像Smalltalk。然而,所有的Python类型在语义上都有一点相同之处:描述 它们的最贴切词语是“对象”。 对象是被特化的,多个名字(在多个作用域中)可以绑定同一个对象。这相当于其它语言中的别名。通常 对Python的第一印象中会忽略这一点,使用那些不可变的基本类型(数值、字符串、元组)时也可以很放心的 忽视它。然而,在Python代码调用字典、链表之类可变对象,以及大多数涉及程序外部实体(文件、窗体等 等)的类型时,这一语义就会有影响。这通用有助于优化程序,因为别名的行为在某些方面类似于指针。例 如,很容易传递一个对象,因为在行为上只是传递了一个指针。如果函数修改了一个通过参数传递的对象,调 用者可以接收到变化--在Pascal中这需要两个不同的参数传递机制。 9.2 Python 作用域和命名空间 在介绍类之前,我首先介绍一些有关Python作用域的规则:类的定义非常巧妙的运用了命名空间,要完全理解 接下来的知识,需要先理解作用域和命名空间的工作原理。另外,这一切的知识对于任何高级Python程序员都 非常有用。 我们从一些定义开始。 命名空间是从命名到对象的映射。当前命名空间主要是通过Python字典实现的,不过通常不关心具体的实现方 式(除非出于性能考虑),以后也有可能会改变其实现方式。以下有一些命名空间的例子:内置命名(像 abs() 这样的函数,以及内置异常名)集,模块中的全局命名,函数调用中的局部命名。某种意义上讲对象的属性集 也是一个命名空间。关于命名空间需要了解的一件很重要的事就是不同命名空间中的命名没有任何联系,例如 两个不同的模块可能都会定义一个名为“maximize”的函数而不会发生混淆--用户必须以模块名为前缀来引 用它们。 顺便提一句,我称Python中任何一个“.”之后的命名为属性--例如,表达式z.real中的real是对象z的一个属 性。严格来讲,从模块中引用命名是引用属性:表达式 modname.funcname中,modname 是一个模块对象, funcname 是它的一个属性。因此,模块的属性和模块中的全局命名有直接的映射关系:它们共享同一命名空 间! 9.1 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 属性可以是只读过或写的。后一种情况下,可以对属性赋值。你可以这样作:“modname.the_answer = 42”。 可写的属性也可以用del语句删除。例如:“del modname.the_answer”会从 modname对象中删除the_answer 属 性。 不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在Python解释器启动时创建, 会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到 解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都 是__main__模块的一部分,所以它们也拥有自己的命名空间。(内置命名也同样被包含在一个模块中,它被称 作__builtin__。) 当函数被调用时创建一个局部命名空间,函数反正返回过抛出一个未在函数内处理的异常时删除。(实际上, 说是遗忘更为贴切)。当然,每一个递归调用拥有自己的命名空间。 作用域是指Python程序可以直接访问到的命名空间。“直接访问”在这里意味着访问命名空间中的命名时无需 加入附加的修饰符。 尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有三个命名空间可以直接访问的作用域 嵌套在一起:包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中层的作用域,这里包含了同级的 函数;最后搜索最外面的作用域,它包含内置命名。 如果一个命名声明为全局的,那么所有的赋值和引用都直接针对包含模全局命名的中级作用域。另外,从外部 访问到的所有内层作用域的变量都是只读的。 从文本意义上讲,局部作用域引用当前函数的命名。在函数之外,局部作用域与全局使用域引用同一命名空 间:模块命名空间。类定义也是局部作用域中的另一个命名空间。 作用域决定于源程序的文本:一个定义于某模块中的函数的全局作用域是该模块的命名空间,而不是该函数的 别名被定义或调用的位置,了解这一点非常重要。另一方面,命名的实际搜索过程是动态的,在运行时确定的 ——然而,Python语言也在不断发展,以后有可能会成为静态的“编译”时确定,所以不要依赖于动态解析! (事实上,局部变量已经是静态确定了。) Python的一个特别之处在于其赋值操作总是在最里层的作用域。赋值不会复制数据——只是将命名绑定到对 象。删除也是如此:“del x ”只是从局部作用域的命名空间中删除命名x。事实上,所有引入新命名的操作都作 用于局部作用域。特别是import语句和函数定将模块名或函数绑定于局部作用域。(可以使用global语句将变量 引入到全局作用域。) 9.3 初识类 类引入了一点新的语法,三种新的对象类型,以及一些新的语义。 9.3.1 类定义语法 最简单的类定义形式如下: class ClassName: 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] . . . 类的定义就像函数定义(def语句),要先执行才能生效。(你当然可以把它放进if语句的某一分支,或者一个 函数的内部。) 习惯上,类定义语句的内容通常是函数定义,不过其它语句也可以,有时会很有用——后面我们再回过头来讨 论。类中的函数定义通常包括了一个特殊形式的参数列表,用于方法调用约定——同样我们在后面讨论这些。 定义一个类的时候,会创建一个新的命名空间,将其作为局部作用域使用——因此,所以对局部变量的赋值都 引入新的命名空间。特别是函数定义将新函数的命名绑定于此。 类定义完成时(正常退出),就创建了一个类对象。基本上它是对类定义创建的命名空间进行了一个包装;我 们在下一节进一步学习类对象的知识。原始的局部作用域(类定义引入之前生效的那个)得到恢复,类对象在 这里绑定到类定义头部的类名(例子中是ClassName)。 9.3.2 类对象 类对象支持两种操作:属性引用和实例化。 属性引用使用和Python中所有的属性引用一样的标准语法: obj.name。类对象创建后,类命名空间中所有的命 名都是有效属性名。所以如果类定义是这样: class MyClass: "A simple example class" i = 12345 def f(self): return 'hello world' 那么 MyClass.i 和 MyClass.f 是有效的属性引用,分别返回一个整数和一个方法对象。也可以对类属性赋值, 你可以通过给 MyClass.i 赋值来修改它。 __doc__ 也是一个有效的属性,返回类的文档字符串:“A simple example class”。 类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。例如(假设沿用前面 的类) : x = MyClass() 以上创建了一个新的类实例并将该对象赋给局部变量x。 这个实例化操作(“调用”一个类对象)来创建一个空的对象。很多类都倾向于将对象创建为有初始状态的。 因此类可能会定义一个名为__init__() 的特殊方法,像下面这样: def __init__(self): self.data = [] 类定义了 __init__() 方法的话,类的实例化操作会自动为新创建的类实例调用 __init__() 方法。所以在下例 中,可以这样创建一个新的实例: x = MyClass() 当然,出于弹性的需要, __init__() 方法可以有参数。事实上,参数通过 __init__()传递到类的实例化操作上。例 如: 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] >>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5) 9.3.3 实例对象 现在我们可以用实例对象作什么?实例对象唯一可用的操作就是属性引用。有两种有效的属性名。 第一种称作数据属性。这相当于Smalltalk中的“实例变量”或C++中的“数据成员”。和局部变量一样,数据 属性不需要声明,第一次使用时它们就会生成。例如,如果x是前面创建的MyClass 实例,下面这段代码会打印 出16而不会有任何多余的残留: x.counter = 1 while x.counter < 10: x.counter = x.counter * 2 print x.counter del x.counter 第二种为实例对象所接受的引用属性是方法。方法是属于一个对象的函数。(在Python中,方法不止是类实例 所独有:其它类型的对象也可有方法。例如,链表对象有append,insert,remove,sort等等方法。然而,在这 里,除非特别说明,我们提到的方法特指类方法) 实例对象的有效名称依赖于它的类。按照定义,类中所有(用户定义)的函数对象对应它的实例中的方法。所 以在我们的例子中,x..f是一个有效的方法引用,因为MyClass.f是一个函数。但x.i不是,因为MyClass.i是不是 函数。不过x.f和MyClass.f不同--它是一个 方法对象,不是一个函数对象。 9.3.4 方法对象 通常方法是直接调用的: x.f() 在我们的例子中,这会返回字符串‘hello world’。然而,也不是一定要直接调用方法。x.f是一个方法对象,它可以存储起 来以后调用。例如: xf = x.f while True: print xf() 会不断的打印“Hello world”。 调用方法时发生了什么?你可能注意到调用 x.f() 时没有引用前面标出的变量,尽管在f的函数定义中指明了 一个参数。这个参数怎么了?事实上如果函数调用中缺少参数,Python会抛出异常--甚至这个参数实际上没 什么用…… 实际上,你可能已经猜到了答案:方法的特别之处在于实例对象作为函数的第一个参数传给了函数。在我们的 例子中,调用x.f() 相当于MyClass.f(x)。通常,以n个参数的列表去调用一个方法就相当于将方法的对象插入 到参数列表的最前面后,以这个列表去调用相应的函数。 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 如果你还是不理解方法的工作原理,了解一下它的实现也许有帮助。引用非数据属性的实例属性时,会搜索它 的类。如果这个命名确认为一个有效的函数对象类属性,就会将实例对象和函数对象封装进一个抽象对象:这 就是方法对象。以一个参数列表调用方法对象时,它被重新拆封,用实例对象和原始的参数列表构造一个新的 参数列表,然后函数对象调用这个新的参数列表。 9.4 一些说明 〔有些内容可能需要明确一下……〕 同名的数据属性会覆盖方法属性,为了避免可能的命名冲突--这在大型程序中可能会导致难以发现的bug- -最好以某种命名约定来避免冲突。可选的约定包括方法的首字母大写,数据属性名前缀小写(可能只是一个 下划线),或者方法使用动词而数据属性使用名词。 数据属性可以由方法引用,也可以由普通用户(客户)调用。换句话说,类不能实现纯的数据类型。事实 上,Python中没有什么办法可以强制隐藏数据--一切都基本约定的惯例。(另一方法讲,Python的实现是 用C写成的,如果有必要,可以用C来编写Python扩展,完全隐藏实现的细节,控制对象的访问。) 客户应该小心使用数据属性--客户可能会因为随意修改数据属性而破坏了本来由方法维护的数据一致性。需 要注意的是,客户只要注意避免命名冲突,就可以随意向实例中添加数据属性而不会影响方法的有效性--再 次强调,命名约定可以省去很多麻烦。 从方法内部引用数据属性(以及其它方法!)没有什么快捷的方式。我认为这事实上增加了方法的可读性:即 使粗略的浏览一个方法,也不会有混淆局部变量和实例变量的机会。 习惯上,方法的第一个参数命名为 self。这仅仅是一个约定:对Python而言,self 绝对没有任何特殊含义。 (然而要注意的是,如果不遵守这个约定,别的Python程序员阅读你的代码时会有不便,而且有些类浏览程序 也是遵循此约定开发的。) 类属性中的任何函数对象在类实例中都定义为方法。不是必须要将函数定义代码写进类定义中,也可以将一个 函数对象赋给类中的一个变量。例如: # Function defined outside the class def f1(self, x, y): return min(x, x+y) class C: f = f1 def g(self): return 'hello world' h = g 现在 f, g 和 h 都是类C的属性,引用的都是函数对象,因此它们都是C实例的方法--h严格等于g。要注意的 是这种习惯通常只会迷惑程序的读者。 通过 self 参数的方法属性,方法可以调用其它的方法: class Bag: def __init__(self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] self.add(x) 方法可以像引用普通的函数那样引用全局命名。与方法关联的全局作用域是包含类定义的模块。(类本身永远 不会做为全局作用域使用!)尽管很少有好的理由在方法中使用全局数据,全局作用域确有很多合法的用途: 其一是方法可以调用导入全局作用域的函数和方法,也可以调用定义在其中的类和函数。通常,包含此方法的 类也会定义在这个全局作用域,在下一节我们会了解为何一个方法要引用自己的类! 9.5 继承 当然,如果一种语言不支持继承就,“类”就没有什么意义。派生类的定义如下所示: class DerivedClassName(BaseClassName): . . . 命名 BaseClassName (示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类 定义在另一个模块中时这一点非常有用: class DerivedClassName(modname.BaseClassName): 派生类定义的执行过程和基类是一样的。构造派生类对象时,就记住了基类。这在解析属性引用的时候尤其有 用:如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归的应用 上去。 派生类的实例化没有什么特殊之处:DerivedClassName() (示列中的派生类)创建一个新的类实例。方法引用 按如下规则解析:搜索对应的类属性,必要时沿基类链逐级搜索,如果找到了函数对象这个方法引用就是合法 的。 派生类可能会覆盖其基类的方法。因为方法调用同一个对象中的其它方法时没有特权,基类的方法调用同一个 基类的方法时,可能实际上最终调用了派生类中的覆盖方法。(对于C++程序员来说,Python中的所有方法本 质上都是虚方法。) 派生类中的覆盖方法可能是想要扩充而不是简单的替代基类中的重名方法。有一个简单的方法可以直接调用基 类方法,只要调用:“BaseClassName.methodname(self, arguments)”。有时这对于客户也很有用。(要注意 的中只有基类在同一全局作用域定义或导入时才能这样用。) 9.5.1 多继承 Python同样有限的支持多继承形式。多继承的类定义形如下例: class DerivedClassName(Base1, Base2, Base3): . . . 这里唯一需要解释的语义是解析类属性的规则。顺序是深度优先,从左到右。因此,如果在 DerivedClassName 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] (示例中的派生类)中没有找到某个属性,就会搜索 Base1 ,然后(递归的)搜索其基类,如果最终没有找到,就搜索 Base2,以此类推。 (有些人认为广度优先--在搜索Base1的基类之前搜索Base2和Base3--看起来更为自然。然而,如 果Base1和Base2之间发生了命名冲突,你需要了解这个属性是定义于Base1还是Base1的基类中。而深度优先不 区分属性继承自基类还是直接定义。) 显然不加限制的使用多继承会带来维护上的噩梦,因为Python中只依靠约定来避免命名冲突。多继承一个很有 名的问题是派生继承的两个基类都是从同一个基类继承而来。目前还不清楚这在语义上有什么意义,然而很容 易想到这会造成什么后果(实例会有一个独立的“实例变量”或数据属性复本作用于公共基类。) 9.6 私有变量 Python对类的私有成员提供了有限的支持。任何形如__spam (以至少双下划线开头,至多单下划线结尾)随即 都被替代为 _classname__spam, 去掉前导下划线的classname 即当前的类名。这种混淆不关心标识符的语法位 置,所以可用来定义私有类实例和类变量、方法,以及全局变量,甚至于将其它类的实例保存为私有变量。混 淆名长度超过255个字符的时候可能会发生截断。在类的外部,或类名只包含下划线时,不会发生截断。 命名混淆意在给出一个在类中定义“私有”实例变量和方法的简单途径,避免派生类的实例变量定义产生问 题,或者与外界代码中的变量搞混。要注意的是混淆规则主要目的在于避免意外错误,被认作为私有的变量仍 然有可能被访问或修改。在特定的场合它也是有用的,比如调试的时候,这也是一直没有堵上这个漏洞的原因 之一(小漏洞:派生类和基类取相同的名字就可以使用基类的私有变量。) 要注意的是传入exec,eval()或evalfile()的代码不会将调用它们的类视作当前类,这与global语句的情况类 似,global的作用局限于“同一批”进行字节编译的代码。同样的限制也适用于getattr() ,setattr()和delattr(), 以及直接引用__dict__的时候。 9.7 补充 有时类似于Pascal中“记录(record)”或C中“结构(struct)”的数据类型很有用,它将一组已命名的数据项 绑定在一起。一个空的类定义可以很好的实现这它: class Employee: pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000 某一段Python代码需要一个特殊的抽象数据结构的话,通常可以传入一个类,事实上这模仿了该类的方法。例 如,如果你有一个用于从文件对象中格式化数据的函数,你可以定义一个带有Read()和Readline()方法的类,以 此从字符串缓冲读取数据,然后将该类的对象作为参数传入前述的函数。 实例方法对象也有属性: m.im_self 是一个实例方法所属的对象,而 m.im_func 是这个方法对应的函数对象。 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 9.8 异常也是类 用户自定义异常也可以是类。利用这个机制可以创建可扩展的异常体系。 以下是两种新的有效(语义上的)异常抛出形式: raise Class, instance raise instance 第一种形式中,instance 必须是 Class 或其派生类的一个实例。第二种形式是以下形式的简写: raise instance.__class__, instance 发生的异常其类型如果是异常子句中列出的类,或者是其派生类,那么它们就是相符的(反过来说--发生的 异常其类型如果是异常子句中列出的类的基类,它们就不相符)。例如,以下代码会按顺序打印B,C,D: class B: pass class C(B): pass class D(C): pass for c in [B, C, D]: try: raise c() except D: print "D" except C: print "C" except B: print "B" 要注意的是如果异常子句的顺序颠倒过来(“execpt B”在最前),它就会打印B,B,B--第一个匹配的异常 被触发。 打印一个异常类的错误信息时,先打印类名,然后是一个空格、一个冒号,然后是用内置函数str()将类转换得 到的完整字符串。 9.9 迭代器 现在你可能注意到大多数容器对象都可以用 for 遍历: for element in [1, 2, 3]: print element for element in (1, 2, 3): print element for key in {'one':1, 'two':2}: print key for char in "123": print char for line in open("myfile.txt"): print line 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 这种形式的访问清晰、简洁、方便。这种迭代器的用法在Python中普遍而且统一。在后台,for 语句在容器对 象中调用 iter() 。 该函数返回一个定义了 next() 方法的迭代器对象,它在容器中逐一访问元素。没有后续的 元素时,next() 抛出一个 StopIteration 异常通知 for 语句循环结束。以下是其工作原理的示例: >>> s = 'abc' >>> it = iter(s) >>> it >>> it.next() 'a' >>> it.next() 'b' >>> it.next() 'c' >>> it.next() Traceback (most recent call last): File "", line 1, in -toplevel- it.next() StopIteration 了解了迭代器协议的后台机制,就可以很容易的给自己的类添加迭代器行为。定义一个 __iter__() 方法,使 其返回一个带有 next() 方法的对象。如果这个类已经定义了 next(),那么 __iter__() 只需要返回self: >>> class Reverse: "Iterator for looping over a sequence backwards" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def next(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] >>> for char in Reverse('spam'): print char m a p s 9.10 发生器 发生器是创建迭代器的简单而强大的工具。它们写起来就像是正则函数,需要返回数据的时候使用yield 语 句。每次 next() 被调用时,生成器回复它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)。 以下示例演示了发生器可以很简单的创建出来: >>> def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index] >>> for char in reverse('golf'): print char f l o g 前一节中描述了基于类的迭代器,它能作的每一件事发生器也能作到。因为自动创建了 __iter__() 和 next() 方法,发生器显得如此简洁。 9. 类 file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node11.html[09-5-21 ••08:01:38] 另外一个关键的功能是两次调用之间的局部变量和执行情况都自动保存了下来。这样函数编写起来就比手动调 用 self.index 和 self.data 这样的类变量容易的多。 除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration异常。综上所述,这些功能使得 编写一个正则函数成为创建迭代器的最简单方法。 Footnotes ... 命名空间!9.1 有一个例外。模块对象有一个隐秘的只读对象,名为 __dict__ ,它返回用于实现模块命名空间的字典, 命名 __dict__ 是一个属性而非全局命名。显然,使用它违反了命名空间实现的抽象原则,应该被严格限 制于调试中。 Python 指南 向前: 8. 错误和异常 向上: Python 指南 向后: 10. 接下来? Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. Python中文社区 10. What Now? file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node12.html[09-5-21 ••08:01:43] PythonÖÐÎÄÉçÇø Python Tutorial Previous: 9. Classes Up: Python Tutorial Next: A. Interactive Input Editing 10. What Now? Reading this tutorial has probably reinforced your interest in using Python -- you should be eager to apply Python to solve your real-world problems. Now what should you do? You should read, or at least page through, the Python Library Reference, which gives complete (though terse) reference material about types, functions, and modules that can save you a lot of time when writing Python programs. The standard Python distribution includes a lot of code in both C and Python; there are modules to read UNIX mailboxes, retrieve documents via HTTP, generate random numbers, parse command-line options, write CGI programs, compress data, and a lot more; skimming through the Library Reference will give you an idea of what's available. The major Python Web site is http://www.python.org/; it contains code, documentation, and pointers to Python- related pages around the Web. This Web site is mirrored in various places around the world, such as Europe, Japan, and Australia; a mirror may be faster than the main site, depending on your geographical location. A more informal site is http://starship.python.net/, which contains a bunch of Python-related personal home pages; many people have downloadable software there. Many more user-created Python modules can be found in a third-party repository at http://www.vex.net/parnassus. For Python-related questions and problem reports, you can post to the newsgroup comp.lang.python, or send them to the mailing list at python-list@python.org. The newsgroup and mailing list are gatewayed, so messages posted to one will automatically be forwarded to the other. There are around 120 postings a day (with peaks up to several hundred), asking (and answering) questions, suggesting new features, and announcing new modules. Before posting, be sure to check the list of Frequently Asked Questions (also called the FAQ), at http://www.python.org/doc/FAQ.html, or look for it in the Misc/ directory of the Python source distribution. Mailing list archives are available at http://www.python.org/pipermail/. The FAQ answers many of the questions that come up again and again, and may already contain the solution for your problem. Python Tutorial Previous: 9. Classes Up: Python Tutorial Next: A. Interactive Input Editing Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. PythonÖÐÎÄÉçÇø A. Interactive Input Editing and History Substitution file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node13.html[09-5-21 ••08:01:44] PythonÖÐÎÄÉçÇø Python Tutorial Previous: 10. What Now? Up: Python Tutorial Next: B. Floating Point Arithmetic: Subsections A.1 Line Editing A.2 History Substitution A.3 Key Bindings A.4 Commentary A. Interactive Input Editing and History Substitution Some versions of the Python interpreter support editing of the current input line and history substitution, similar to facilities found in the Korn shell and the GNU Bash shell. This is implemented using the GNU Readline library, which supports Emacs-style and vi-style editing. This library has its own documentation which I won't duplicate here; however, the basics are easily explained. The interactive editing and history described here are optionally available in the UNIX and CygWin versions of the interpreter. This chapter does not document the editing facilities of Mark Hammond's PythonWin package or the Tk-based environment, IDLE, distributed with Python. The command line history recall which operates within DOS boxes on NT and some other DOS and Windows flavors is yet another beast. A.1 Line Editing If supported, input line editing is active whenever the interpreter prints a primary or secondary prompt. The current line can be edited using the conventional Emacs control characters. The most important of these are: C-A (Control-A) moves the cursor to the beginning of the line, C-E to the end, C-B moves it one position to the left, C-F to the right. Backspace erases the character to the left of the cursor, C-D the character to its right. C-K kills (erases) the rest of the line to the right of the cursor, C-Y yanks back the last killed string. C-underscore undoes the last change you made; it can be repeated for cumulative effect. A.2 History Substitution History substitution works as follows. All non-empty input lines issued are saved in a history buffer, and when a new prompt is given you are positioned on a new line at the bottom of this buffer. C-P moves one line up (back) in the history buffer, C-N moves one down. Any line in the history buffer can be edited; an asterisk appears in front of the prompt to mark a line as modified. Pressing the Return key passes the current line to the interpreter. C-R starts an incremental reverse search; C-S starts a forward search. A. Interactive Input Editing and History Substitution file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node13.html[09-5-21 ••08:01:44] A.3 Key Bindings The key bindings and some other parameters of the Readline library can be customized by placing commands in an initialization file called ~/.inputrc. Key bindings have the form key-name: function-name or "string": function-name and options can be set with set option-name value For example: # I prefer vi-style editing: set editing-mode vi # Edit using a single line: set horizontal-scroll-mode On # Rebind some keys: Meta-h: backward-kill-word "\C-u": universal-argument "\C-x\C-r": re-read-init-file Note that the default binding for Tab in Python is to insert a Tab character instead of Readline's default filename completion function. If you insist, you can override this by putting Tab: complete in your ~/.inputrc. (Of course, this makes it harder to type indented continuation lines.) Automatic completion of variable and module names is optionally available. To enable it in the interpreter's interactive mode, add the following to your startup file:A.1 import rlcompleter, readline readline.parse_and_bind('tab: complete') This binds the Tab key to the completion function, so hitting the Tab key twice suggests completions; it looks at Python statement names, the current local variables, and the available module names. For dotted expressions such as string.a, it will evaluate the the expression up to the final "." and then suggest completions from the attributes of the resulting object. Note that this may execute application-defined code if an object with a __getattr__() method is part of the expression. A more capable startup file might look like this example. Note that this deletes the names it creates once they are no longer needed; this is done since the startup file is executed in the same namespace as the interactive commands, and removing the names avoids creating side effects in the interactive environments. You may find it convenient to keep some of the imported modules, such as os, which turn out to be needed in most sessions with the interpreter. # Add auto-completion and a stored history file of commands to your Python # interactive interpreter. Requires Python 2.0+, readline. Autocomplete is # bound to the Esc key by default (you can change it - see readline docs). # # Store the file in ~/.pystartup, and set an environment variable to point # to it: "export PYTHONSTARTUP=/max/home/itamar/.pystartup" in bash. # # Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the # full path to your home directory. import atexit import os import readline import rlcompleter historyPath = os.path.expanduser("~/.pyhistory") A. Interactive Input Editing and History Substitution file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node13.html[09-5-21 ••08:01:44] def save_history(historyPath=historyPath): import readline readline.write_history_file(historyPath) if os.path.exists(historyPath): readline.read_history_file(historyPath) atexit.register(save_history) del os, atexit, readline, rlcompleter, save_history, historyPath A.4 Commentary This facility is an enormous step forward compared to earlier versions of the interpreter; however, some wishes are left: It would be nice if the proper indentation were suggested on continuation lines (the parser knows if an indent token is required next). The completion mechanism might use the interpreter's symbol table. A command to check (or even suggest) matching parentheses, quotes, etc., would also be useful. Footnotes ... file:A.1 Python will execute the contents of a file identified by the PYTHONSTARTUP environment variable when you start an interactive interpreter. Python Tutorial Previous: 10. What Now? Up: Python Tutorial Next: B. Floating Point Arithmetic: Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. PythonÖÐÎÄÉçÇø B. Floating Point Arithmetic: Issues and Limitations file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node14.html[09-5-21 ••08:01:45] PythonÖÐÎÄÉçÇø Python Tutorial Previous: A. Interactive Input Editing Up: Python Tutorial Next: C. History and License Subsections B.1 Representation Error B. Floating Point Arithmetic: Issues and Limitations Floating-point numbers are represented in computer hardware as base 2 (binary) fractions. For example, the decimal fraction 0.125 has value 1/10 + 2/100 + 5/1000, and in the same way the binary fraction 0.001 has value 0/2 + 0/4 + 1/8. These two fractions have identical values, the only real difference being that the first is written in base 10 fractional notation, and the second in base 2. Unfortunately, most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers you enter are only approximated by the binary floating-point numbers actually stored in the machine. The problem is easier to understand at first in base 10. Consider the fraction 1/3. You can approximate that as a base 10 fraction: 0.3 or, better, 0.33 or, better, 0.333 and so on. No matter how many digits you're willing to write down, the result will never be exactly 1/3, but will be an increasingly better approximation to 1/3. In the same way, no matter how many base 2 digits you're willing to use, the decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base 2, 1/10 is the infinitely repeating fraction 0.0001100110011001100110011001100110011001100110011... Stop at any finite number of bits, and you get an approximation. This is why you see things like: >>> 0.1 0.10000000000000001 On most machines today, that is what you'll see if you enter 0.1 at a Python prompt. You may not, though, because the number of bits used by the hardware to store floating-point values can vary across machines, and Python only prints a B. Floating Point Arithmetic: Issues and Limitations file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node14.html[09-5-21 ••08:01:45] decimal approximation to the true decimal value of the binary approximation stored by the machine. On most machines, if Python were to print the true decimal value of the binary approximation stored for 0.1, it would have to display >>> 0.1 0.1000000000000000055511151231257827021181583404541015625 instead! The Python prompt (implicitly) uses the builtin repr() function to obtain a string version of everything it displays. For floats, repr(float) rounds the true decimal value to 17 significant digits, giving 0.10000000000000001 repr(float) produces 17 significant digits because it turns out that's enough (on most machines) so that eval(repr(x)) == x exactly for all finite floats x, but rounding to 16 digits is not enough to make that true. Note that this is in the very nature of binary floating-point: this is not a bug in Python, it is not a bug in your code either, and you'll see the same kind of thing in all languages that support your hardware's floating-point arithmetic (although some languages may not display the difference by default, or in all output modes). Python's builtin str() function produces only 12 significant digits, and you may wish to use that instead. It's unusual for eval(str(x)) to reproduce x, but the output may be more pleasant to look at: >>> print str(0.1) 0.1 It's important to realize that this is, in a real sense, an illusion: the value in the machine is not exactly 1/10, you're simply rounding the display of the true machine value. Other surprises follow from this one. For example, after seeing >>> 0.1 0.10000000000000001 you may be tempted to use the round() function to chop it back to the single digit you expect. But that makes no difference: >>> round(0.1, 1) 0.10000000000000001 The problem is that the binary floating-point value stored for "0.1" was already the best possible binary approximation to 1/10, so trying to round it again can't make it better: it was already as good as it gets. Another consequence is that since 0.1 is not exactly 1/10, adding 0.1 to itself 10 times may not yield exactly 1.0, either: >>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989 Binary floating-point arithmetic holds many surprises like this. The problem with "0.1" is explained in precise detail below, in the "Representation Error" section. See The Perils of Floating Point for a more complete account of other common surprises. As that says near the end, ``there are no easy answers.'' Still, don't be unduly wary of floating-point! The errors in Python float operations are inherited from the floating-point hardware, and on most machines are on the order of no more than 1 part in 2**53 per operation. That's more than adequate for most tasks, but you do need to keep in mind that it's not decimal arithmetic, and that every float operation can suffer a new rounding error. While pathological cases do exist, for most casual use of floating-point arithmetic you'll see the result you expect in the end if you simply round the display of your final results to the number of decimal digits you expect. str() usually B. Floating Point Arithmetic: Issues and Limitations file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node14.html[09-5-21 ••08:01:45] suffices, and for finer control see the discussion of Pythons's % format operator: the %g, %f and %e format codes supply flexible and easy ways to round float results for display. B.1 Representation Error This section explains the ``0.1'' example in detail, and shows how you can perform an exact analysis of cases like this yourself. Basic familiarity with binary floating-point representation is assumed. Representation error refers to that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many others) often won't display the exact decimal number you expect: >>> 0.1 0.10000000000000001 Why is that? 1/10 is not exactly representable as a binary fraction. Almost all machines today (November 2000) use IEEE-754 floating point arithmetic, and almost all platforms map Python floats to IEEE-754 "double precision". 754 doubles contain 53 bits of precision, so on input the computer strives to convert 0.1 to the closest fraction it can of the form J/2**N where J is an integer containing exactly 53 bits. Rewriting 1 / 10 ~= J / (2**N) as J ~= 2**N / 10 and recalling that J has exactly 53 bits (is >= 2**52 but < 2**53), the best value for N is 56: >>> 2L**52 4503599627370496L >>> 2L**53 9007199254740992L >>> 2L**56/10 7205759403792793L That is, 56 is the only value for N that leaves J with exactly 53 bits. The best possible value for J is then that quotient rounded: >>> q, r = divmod(2L**56, 10) >>> r 6L Since the remainder is more than half of 10, the best approximation is obtained by rounding up: >>> q+1 7205759403792794L Therefore the best possible approximation to 1/10 in 754 double precision is that over 2**56, or 7205759403792794 / 72057594037927936 Note that since we rounded up, this is actually a little bit larger than 1/10; if we had not rounded up, the quotient would have been a little bit smaller than 1/10. But in no case can it be exactly 1/10! So the computer never ``sees'' 1/10: what it sees is the exact fraction given above, the best 754 double approximation it can get: >>> .1 * 2L**56 7205759403792794.0 If we multiply that fraction by 10**30, we can see the (truncated) value of its 30 most significant decimal digits: B. Floating Point Arithmetic: Issues and Limitations file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node14.html[09-5-21 ••08:01:45] >>> 7205759403792794L * 10L**30 / 2L**56 100000000000000005551115123125L meaning that the exact number stored in the computer is approximately equal to the decimal value 0.100000000000000005551115123125. Rounding that to 17 significant digits gives the 0.10000000000000001 that Python displays (well, will display on any 754-conforming platform that does best-possible input and output conversions in its C library -- yours may not!). Python Tutorial Previous: A. Interactive Input Editing Up: Python Tutorial Next: C. History and License Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. PythonÖÐÎÄÉçÇø C. History and License file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node15.html[09-5-21 ••08:01:46] PythonÖÐÎÄÉçÇø Python Tutorial Previous: B. Floating Point Arithmetic: Up: Python Tutorial Next: About this document ... Subsections C.1 History of the software C.2 Terms and conditions for accessing or otherwise using Python C. History and License C.1 History of the software Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl/) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us/) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation; see http://www.zope.com/). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org/ for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived from Year Owner GPL compatible? 0.9.0 thru 1.2 n/a 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI no 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.2 2.1.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2.1 2.2 2002 PSF yes 2.2.2 2.2.1 2002 PSF yes 2.2.3 2.2.2 2002-2003 PSF yes 2.3 2.2.2 2002-2003 PSF yes Note: GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the C. History and License file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node15.html[09-5-21 ••08:01:46] GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. C.2 Terms and conditions for accessing or otherwise using Python PSF LICENSE AGREEMENT FOR PYTHON 2.3 1. This LICENSE AGREEMENT is between the Python Software Foundation (``PSF''), and the Individual or Organization (``Licensee'') accessing and otherwise using Python 2.3 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 2.3 alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., ``Copyright © 2001-2003 Python Software Foundation; All Rights Reserved'' are retained in Python 2.3 alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 2.3 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 2.3. 4. PSF is making Python 2.3 available to Licensee on an ``AS IS'' basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python 2.3, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com (``BeOpen''), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization (``Licensee'') accessing and otherwise using this software in source or binary form and its associated documentation (``the Software''). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee C. History and License file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node15.html[09-5-21 ••08:01:46] a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an ``AS IS'' basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the ``BeOpen Python'' logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 (``CNRI''), and the Individual or Organization (``Licensee'') accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., ``Copyright © 1995-2001 Corporation for National Research Initiatives; All Rights Reserved'' are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): ``Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013.'' 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an ``AS IS'' basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. C. History and License file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node15.html[09-5-21 ••08:01:46] 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the ``ACCEPT'' button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 Copyright © 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Python Tutorial Previous: B. Floating Point Arithmetic: Up: Python Tutorial Next: About this document ... Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. PythonÖÐÎÄÉçÇø About this document ... file:///Users/moon/Incoming/py/doc.chinahtml.com/Manual/Python/tut/node16.html[09-5-21 ••08:01:47] PythonÖÐÎÄÉçÇø Python Tutorial Previous: C. History and License Up: Python Tutorial About this document ... Python Tutorial, July 29, 2003, Release 2.3 This document was generated using the LaTeX2HTML translator. LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney. The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli. Comments and Questions General comments and questions regarding this document should be sent by email to python-docs@python.org. If you find specific errors in this document, either in the content or the presentation, please report the bug at the Python Bug Tracker at SourceForge. Questions regarding how to use the information in this document should be sent to the Python news group, comp.lang.python, or the Python mailing list (which is gated to the newsgroup and carries the same content). For any of these channels, please be sure not to send HTML email. Thanks. Python Tutorial Previous: C. History and License Up: Python Tutorial Release 2.3, documentation updated on July 29, 2003. See About this document... for information on suggesting changes. PythonÖÐÎÄÉçÇø
还剩82页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

lyj_101

贡献于2016-09-21

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf