├── README.md └── book ├── 第2章 安装Python.md ├── 前言.md ├── 附录C 修订记录.md ├── 附录B 关于本书.md ├── 附录A 自由&开放源码软件(FLOSS).md ├── 第12章 输入&输出.md ├── 第16章 接下来学习什么?.md ├── 第5章 运算符与表达式.md ├── 第1章 介绍.md ├── 第14章 Python标准库.md ├── 第15章 更多Python的内容.md ├── 第13章 异常.md ├── 第3章 最初的步骤.md ├── 第4章 基本概念.md ├── 第8章 模块.md ├── 第6章 控制流.md ├── 第7章 函数.md ├── 第11章 面向对象的编程.md ├── 第10章 解决问题——编写一个Python脚本.md └── 第9章 数据结构.md /README.md: -------------------------------------------------------------------------------- 1 | 简明 Python 教程 2 | === 3 | ***waroop, C. H.*** *著* ***沈洁元*** *译* 4 | 5 | *www.byteofpython.info* 6 | 7 | 8 | **版本:1.20** 9 | 10 | *A Byte of Python* 11 | 12 | Copyright © 2003-2005 Swaroop C H 13 | 14 | *简明 Python 教程* 15 | 16 | 《简明 Python 教程》为 "A Byte of Python" 的唯一指定简体中文译本,版权 © 2005 沈洁元 17 | 本书依照 [创作公用约定(署名-非派生作品-非商业用途)][ref_BY_ND_NC] 发布。 18 | 19 | **概要** 20 | 21 | 无论您刚接触电脑还是一个有经验的程序员,本书都将有助您学习使用Python语言。 22 | 23 | 24 | --- 25 | 这本书原始的网站在这里: [简明 Python 教程][ref_A_byte_of_Python] , 我只是偶然想学习一下Python,在网上发现了它,一眼觉得这个教程挺好,遂在 `**GitHub** ` 上搜索,没有发现有人把他搬运到 `**GitHub** ` 上。就自己来了,一方面是自己在搬运过程中可以更仔细的阅读这份教程,另一方面最近来学习了 [Markdown][ref_markdown] 也想找点东西练手。 26 | 27 | 在搬运过程中,可能会疏忽的地方,如果你发现了,请告诉我或Fork it 28 | 29 | 30 | [ref_markdown]: http://daringfireball.net/projects/markdown/ 31 | [ref_A_byte_of_Python]: http://woodpecker.org.cn/abyteofpython_cn/chinese/ 32 | [ref_BY_ND_NC]: http://www.creativecommons.org/licenses/by-nd-nc/1.0/deed.zh -------------------------------------------------------------------------------- /book/第2章 安装Python.md: -------------------------------------------------------------------------------- 1 | ## Linux和BSD用户 2 | 如果你正在使用一个Linux的发行版比如Fedora或者Mandrake或者其他(你的选择),或者一个BSD系统比如FreeBSD,那么你可能已经在你的系统里安装了Python。 3 | 4 | 要测试你是否已经随着你的Linux包安装了Python,你可以打开一个shell程序(就像konsole或gnome-terminal)然后输入如下所示的命令 **python -V** 。 5 | 6 | ``` 7 | $ python -V 8 | Python 2.3.4 9 | ``` 10 | 11 | 12 | > **注释:** 13 | 14 | > $是shell的提示符。根据你的操作系统的设置,它可能与你那个不同,因此我只用$符号表示提示符。 15 | 16 | 17 | 如果你看见向上面所示的那样一些版本信息,那么你已经安装了Python了。 18 | 19 | 如果你得到像这样的消息: 20 | 21 | ``` 22 | $ python -V 23 | bash: python: command not found 24 | ``` 25 | 26 | 那么你还没有安装Python。这几乎不可能,只是极其偶尔才会遇到。 27 | 28 | 在这种情况下,你有两种方法在你的系统上安装Python。 29 | 30 | - 利用你的操作系统附带的包管理软件安装二进制包,比如Fedora Linux的yum、Mandrake Linux的urpmi、Debian Linux的apt-get、FreeBSD的pkg_add等等。注意,使用这种方法的话,你需要连接因特网。 31 | 32 | - 你也可以从别的地方下载二进制包然后拷贝到你的PC中安装。 33 | 34 | - 你可以从源代码编译[Python][ref_PyDownload]然后安装。在网站上有编译的指令。 35 | 36 | ## Windows®用户 37 | Windows®用户可以访问Python.org/download,从网站上下载最新的版本(在写本书的时候,最新版本是2.3.4版)。它的大小大约是9.4MB,与其他大多数语言相比是十分紧凑的。安装过程与其他Windows软件类似。 38 | 39 | > **提示** 40 | 41 | > 即便安装程序为你提供了不检查 可选 组件的选项,你也不要不作任何检查!有些组件对你很有用,特别是集成开发环境。 42 | 43 | 有趣的是,大约70%的Python下载是来自Windows用户的。当然,这并不能说明问题,因为几乎所有的Linux用户已经在安装系统的时候默认安装了Python。 44 | 45 | > **在Windows命令行中使用Python** 46 | 47 | >如果你想要从Windows命令行调用Python,那么你需要先正确的设置PATH变量。 48 | 49 | > 对于Windows 2000、XP、2003,点击控制面板->系统->高级->环境变量。在“系统变量”表单中点击叫做 **PATH** 的变量,然后编辑这个变量,把; **C:\Python23** 加到它的结尾。当然,是Python所在的正确目录名。 50 | 51 | > 对于较旧版本的Windows,把下面这行加到文件C:\AUTOEXEC.BAT中: **PATH=%PATH%;C:\Python23** ,然后重新启动系统。对于Windows NT,则使用AUTOEXEC.NT文件。 52 | 53 | ## 概括 54 | 对于Linux系统,很可能你已经在你的系统里安装了Python。否则,你可以通过你的发行版附带的包管理软件安装Python。对于Windows系统,安装Python就是下载安装程序然后双击它那么简单。从现在起,我们将假设你已经在你的系统里安装了Python。 55 | 56 | [ref_PyDownload]: http://www.python.org/download/ -------------------------------------------------------------------------------- /book/前言.md: -------------------------------------------------------------------------------- 1 | Python语言可能是第一种即简单又功能强大的编程语言。它不仅适合于初学者,也适合于专业人员使用,更加重要的是,用Python编程是一种愉快的事。本身将帮助你学习这个奇妙的语言,并且向你展示如何即快捷又方便地完成任务——真正意义上“为编程问题提供的完美解决方案!” 2 | 3 | ## 本书的读者 4 | 本书可以作为Python编程语言的一本指南或者教程。它主要是为新手而设计,不过对于有经验的程序员来说,它同样有用。 5 | 6 | 即便你对计算机的了解只是如何在计算机上保存文本文件,你都可以通过本书学习Python。如果你有编程经验,你也可以使用本书学习Python。 7 | 8 | 如果你以前有编程经验,那么你将会对Python语言和其他你所钟爱的编程语言之间的区别感兴趣。对此我为你指出了许多这样的区别。顺便提醒你,Python将很快成为你最喜欢的编程语言! 9 | 10 | ## 本书的由来 11 | 我最初接触Python是当我需要为我的软件[钻石][ref_1]写一个方便安装过程的安装程序的时候。我得在Python和Perl语言中选择一个绑定Qt库。我在网上做了一些研究,偶然发现了一篇文章。那是Eric S. Raymond(著名的电脑高手)谈Python如何成为它最喜欢地编程语言的一篇文章。我同时发现PyQt绑定与Perl-Qt相比要出色得多,所以我选择了Python语言。 12 | 13 | ## 本书目前的状况 14 | 本书目前仍然在 **进一步完善** 中。许多章节已经频繁地做了修改。然而本书已经十分成熟了,你一定可以很容易地通过它学习Python。如果你觉得本书中有什么错误或者难懂的地方,请告诉我。 15 | 16 | 本书将来计划增加更多的章节,包括wxPython,Twisted,有可能的话甚至还有Boa Constructor。 17 | 18 | ## 官方网站 19 | 本书的官方网站是[www.byteofpython.info][ref_byteofpython]。你可以在这个网站上在线阅读本书,也可以下载本书的最新版本或给我反馈。 20 | 21 | ## 约定条款 22 | 本书(原版)依照创作共用约定([署名-非商业作品-保持一致][ref_BY_ND_NC])发布。简单地说,你只要署上我的名字,就可以免费复制、分发和展示本书。未得到我的允许,你禁止把本书用于商业目的。你在修改本书的时候,必须清楚地标明所有做了改动的地方,你发布修改后的作品时也必须遵照与本书相同的约定。 23 | 24 | 请访问[创作公用约定][ref_BY_NC_SA]的网站浏览约定全文,或者查看一个简单易懂的约定描述。那里还有一个连环画似的约定条款的解释。 25 | 26 | ## 反馈 27 | 我尽了很大的力让这本书即生动又尽可能的准确。然而,如果你找到任何不太令你满意的地方或者错误,或者是需要改进的地方,请告诉我以便我改正它们。你可以把它们通过`swaroop@byteofpython.info`发送给我。 28 | 29 | ## 值得思考的一些东西 30 | >有两种方式构建软件设计:一种是把软件做得很简单以至于明显找不到缺陷;另一种是把它做得很复杂以至于找不到明显的缺陷。 31 | 32 | *C.A.R. Hoare* 33 | 34 | >获得人生中的成功需要的专注与坚持不懈多过天才与机会。 35 | 36 | *C.W. Wendte* 37 | 38 | [ref_1]: http://www.g2swaroop.net/software/ 39 | [ref_byteofpython]: http://www.byteofpython.info/ 40 | [ref_BY_ND_NC]: http://www.creativecommons.org/licenses/by-nd-nc/1.0/deed.zh 41 | [ref_BY_NC_SA]: http://creativecommons.org/licenses/by-nc-sa/2.0/ 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /book/附录C 修订记录.md: -------------------------------------------------------------------------------- 1 | ## 时间表 2 | 本文档在2005年1月13日4点02分生成。 3 | 4 | ### 修订记录 5 | 6 | 版本 | 日期 7 | --- | --- 8 | 1.20版 | 2005年1月13日 9 | |使用FC3上的Quanta+的完全重写。做了许多修正和更新。添加了许多新的例子。重写了我的DocBook设置。 10 | 1.15版| 2004年3月28日 11 | |少量修订。 12 | 1.12版| 2004年3月16日 13 | 添加修正了一些内容。| 14 | 1.10版| 2004年3月9日 15 | 感谢我的热情读者的帮助,我对更多的笔误做了修改。| 16 | 1.00版| 2004年3月8日 17 | 在从读者处获得了大量反馈和建议之后,我对本书的内容做了重要的修订,并且改正了一些笔误。| 18 | 0.99版| 2004年2月22日 19 | 增加了模块一章。增加了对可变数目函数参数的详细介绍。| 20 | 0.98版| 2004年2月16日 21 | 编写了一个Python脚本和CSS样式表来改善XHTML的输出效果。其中包括一个功能还很拙劣的词汇分析器,用来自动地为程序做类似于VIM地语法加亮。| 22 | 0.97版| 2004年2月13日 23 | (再次)使用DocBook XML完全重写。本书改进了许多——更加有条理和易读。| 24 | 0.93版| 2004年1月25日 25 | 增加了关于IDLE的介绍以及更多Windows®相关的话题。| 26 | 0.92版| 2004年1月5日 27 | 修改了几个例子。| 28 | 0.91版| 2003年12月30日 29 | 修正了排版错误。改进了许多章节的内容。| 30 | 0.90版| 2003年12月18日 31 | 增加了2章。使用OpenOffice格式修订。| 32 | 0.60版| 2003年11月21日 33 | 完全地重写和扩展。| 34 | 0.20版| 2003年11月20日 35 | 修改了一些排版错误和其他错误。| 36 | 0.15版| 2003年11月20日 37 | 改用DocBook XML。| 38 | 0.10版| 2003年11月14日 39 | 最初使用KWord编写的草稿。| 40 | 41 | ## 术语表 42 | 43 | EN | CN 44 | --- | --- 45 | argument | 实参 46 | attribute | 属性 47 | base class | 基本类 48 | block | 块 49 | character | 字符 50 | class | 类 51 | comment|注释 52 | complex number|复数 53 | derived class|导出类 54 | dictionary|字典 55 | escape sequence|转义符 56 | exception|异常 57 | expression|表达式 58 | field|域 59 | float|浮点数 60 | function|函数 61 | identifier|标识符 62 | indentation|缩进 63 | indexing|索引 64 | instance|实例 65 | integer|整数 66 | list|列表 67 | list comprehension|列表综合 68 | literal constant|字面意义上的常量 69 | logical line|逻辑行 70 | long integer|长整数 71 | method|方法 72 | module|模块 73 | namespace|名称空间 74 | object|对象 75 | operand|操作数 76 | operator|运算符 77 | parameter|形参 78 | pickle|储存器 79 | physical line|物理行 80 | sequence|序列 81 | shebang line|组织行 82 | slicing|切片 83 | statement|语句 84 | string|字符串 85 | subclass|子类 86 | superclass|超类 87 | tuple|元组 88 | type|类型 89 | variable|变量 -------------------------------------------------------------------------------- /book/附录B 关于本书.md: -------------------------------------------------------------------------------- 1 | ## 后记 2 | 我在编写本书时使用的几乎所有软件都是 免费开放源码的软件 。在编写本书的第一个草稿的时候,我使用的是Red Hat 9.0 Linux,而现在第六次改写的时候,使用的是Fedora Core 3 Linux。 3 | 4 | 最初,我使用KWord编写本书(在前言的本书的由来中已经介绍了)。后来,我开始使用DocBook XML和Kate,但是我发现这样太乏味。所以,我开始使用OpenOffice,它对格式的控制以及生成PDF的能力是很棒的。但是它生成的HTML过于庞大。最后,我发现了XEmacs,于是我又开始重新使用DocBook XML来编写本书,并且那时我打算把这个模式作为将来长期的方案。在这个最新的第六次重写时,我决定使用Quanta+来编辑。 5 | 6 | 我使用了标准的XSL样式表,它随Fedora Core 3 Linux附带。另外,我也使用了标准的默认字体。我编写了一个CSS文件来为HTML页增加颜色和样式。同时,我还用Python语言编写了一个粗劣的词汇分析器,它自动为书中所有的程序进行语法加亮。 7 | 8 | ## 关于作者 9 | Swaroop C. H. 在Yahoo!驻印度班加罗尔的办事处工作,他十分热爱他的工作。他目前在技术领域的兴趣有:包括Linux、DotGNU、Qt和MySQL在内的FLOSS、Python和C#编程语言。另外他在业余时间编写一些如本书这样的教材和其他软件,以及编写他的网上日记。他的其他爱好有咖啡、Robert Ludlum的小说、远足和政治等。 10 | 11 | 如果你有兴趣了解他的更多故事,可以在[www.swaroopch.info](http://www.swaroopch.info/)上查看他的网上日记。 12 | 13 | ## 关于译者 14 | 沈洁元 目前是上海交通大学无线通信研究所的一名硕士研究生。他现在的研究领域主要在多载波CDMA系统的同步、信道估计、多用户检测等方面。Python语言(和Numeric库)是他目前在进行仿真和其他科研工作时使用的主要编程语言。在业余时间,他乐衷于各种FLOSS,如FreeBSD操作系统、PyGTK等等。电影、F1赛车和网球也是他的兴趣爱好。 15 | 16 | ## 关于简体中文译本 17 | 我在半年多前开始学习使用Python编程语言。正如Swaroop在本书中所说的那样,它很快就成为“我最喜欢的编程语言”。目前我的几乎所有编程工作都使用Python。从我的切身体会来说,Python最大的特点就是易懂、易用、高效率。我相信,如果你已经学完了本书,并且尝试着编写了一些程序后,你一定会有相同的感受。 18 | 19 | Swaroop C. H.的这本书是我学习Python时的第一本教材。它简单明晰,可以在最短的时间内把你领进Python的世界。它不是很长,但是覆盖了几乎所有重要的Python知识。在第一次读本书的时候,我就深切的感到这是给Python初学者的一本极佳教材,应该是每一位Python初学者的第一本教材。 20 | 21 | 我利用业余时间翻译了这本教材的简体中文译本。一方面是为了感谢Swaroop给我们带来了那么好的一本教材,同时也是为了把本书介绍给更多的中国读者,希望让Python在中国更加普及。如果读了本书之后,你开始将Python应用于你的工作学习,这将是我和Swaroop以及其他Python用户的荣幸。如果你在学习和使用Python的过程中,遇到任何问题,你一定要试试使用Python的[邮件列表资源](http://mail.python.org/mailman/listinfo)。你一定会得到世界各地的Python高手的热情帮助。 22 | 23 | 本书的英文原名为《A Byte of Python》。经过与Swaroop的探讨,在翻译时,我把书名定为《简明 Python 教程》,以充分体现本书区别于其他Python教材的鲜明特色。在翻译这本简体中文译本时,我力求准确清晰。在原书中个别不甚清晰的地方,都与作者进行讨论后再行翻译。另外,在这本简体中文译本中,我还为书中所有的程序例子配上了源代码,并且在书后附上了中英对照的[术语表](http://woodpecker.org.cn/abyteofpython_cn/chinese/apcs02.html),以便读者以后继续学习其他Python英文资料。 24 | 25 | 本译本作为原书的派生作品,依照[创作公用约定(署名-非派生作品-非商业用途)](http://www.creativecommons.cn/licenses/by-nd-nc/1.0/)发布。简单地说,你只要署上我的名字,就可以免费复制、分发和展示本译本。未得到我的允许,你禁止把本译本用于商业目的,也不能再在本译本的基础上修改、派生新的作品。 26 | 27 | 如果你对本书和译本有任何批评和建议,十分欢迎你与我联系:`orion_val@163.com`。 -------------------------------------------------------------------------------- /book/附录A 自由&开放源码软件(FLOSS).md: -------------------------------------------------------------------------------- 1 | FLOSS基于社区的概念,而它本身基于共享,特别是知识共享的概念。FLOSS可以免费使用、修改和再发行。 2 | 3 | 如果你已经读了本书,那么你一定熟悉FLOSS,因为你一直在使用Python! 4 | 5 | 如果你想要了解更多的FLOSS,你可以探索下面这个列表中的软件。我列出了一些最著名的FLOSS以及那些可以跨平台(即在Linux、Windows等)工作的FLOSS。这样你无需马上切换到Linux就可以尝试使用这些软件了, 尽管你最终一定会转到Linux上的 。 6 | 7 | - Linux 这是一个正在慢慢被世界接纳的FLOSS操作系统!它最初由Linus Torvalds在学生时候开发。现在,它已经可以与微软Windows相匹敌。最新的2.6版本核心,无论从速度、稳定性还是扩展性角度来说,都是一个巨大的突破。【[Linux核心](http://www.kernel.org/)】 8 | 9 | - Knoppix 这是一个仅仅在CD上运行的Linux发行版!它不需要安装——你只需要重新启动你的计算机,把CD放入光驱,就可以开始使用一个完全的Linux发行版了!你可以使用所有的随标准Linux发行版发行的FLOSS,如运行Python程序、编译C程序、看电影等等。然后再次重启你的计算机,取出CD,就可以使用你现有的操作系统了,就好像什么都没有发生过一样。【[Knoppix](http://www.knopper.net/)】 10 | 11 | - Fedora 这是一个由社区开发维护的发行版,由Red Hat公司赞助。它是最流行的Linux发行版之一。它包含Linux核心、KDE、GNOME和XFCE桌面以及众多的FLOSS,而所有这些都易于安装、易于使用。 12 | 13 | - 如果你担心你是一个完全的Linux生手,那么我推荐你尝试Mandrake Linux。最新发布Mandrake 10.1确实很棒。【[Fedora Linux](http://fedora.redhat.com/)、[Mandrake Linux](http://www.mandrakelinux.com/)】 14 | 15 | - OpenOffice.org 这是一个优秀的办公套件,它基于Sun Microsystems的StarOffice软件。OpenOffice由文本编写器、演讲辅助、电子表格和绘图组件等等组成。它甚至可以方便地打开和编辑微软Word和PowerPoint文件。它可以在几乎所有平台上运行。即将推出的OpenOffice 2.0有一些重大的改进。【[OpenOffice](http://www.openoffice.org/)】 16 | 17 | - Mozilla Firefox 这是被认为可以在未来几年击败Internet Explorer(仅按照市场份额计算)的下一代网络浏览器。它极快,它的一些合理的、令人印象深刻的特性广受好评。它的扩展理念允许在它上面添加各种功能。 18 | 19 | - 它的姐妹产品Thunderbird是一个优秀的电子邮件客户端,使阅读电子邮件变得十分快捷。【[Mozilla Firefox](http://www.mozilla.org/products/firefox)、[Mozilla Thunderbird](http://www.mozilla.org/products/thunderbird)】 20 | 21 | - Mono 这是一个微软.NET平台的开源实现。它使我们可以在Linux、Windows、FreeBSD、Mac OS和许多其他平台上创建和运行.NET程序。Mono执行CLI和C#的ECMA标准,这个标准已经由微软、英特尔和惠普提交称为一个开放标准。这也是迈向ISO标准的一步。 22 | 23 | - 目前,Mono包含一个完整的C#主控制台(它本身也由C#编写!)、一个具备完整特性的ASP.NET实现、许多数据库ADO.NET提供器另外还有每天不断改善和增加的新特性。【[Mono](http://www.mono-project.com/)、[ECMA](http://www.ecma-international.org/)、[Microsoft .NET](http://www.microsoft.com/net)】 24 | 25 | - Apache网络服务器 这是最流行的开源网络服务器。事实上,它是地球上最流行的网络服务器!它运行着几乎60%的网站。对——Apache处理的网站比它所有的竞争对手(包括微软IIS)之和还要多。【[Apache](http://www.apache.org/)】 26 | 27 | - MySQL 这是一个极其流行的开源数据库服务器。它以它的快速最为著名。在它的最新版本中又添加了更多的特性。【[MySQL](http://www.mysql.com/)】 28 | 29 | - MPlayer 这是一个视频播放器,可以播放DivX、MP3、Ogg、VCD、DVD……谁说开源软件就不能具有趣味呢?【[MPlayer](http://www.mplayerhq.hu/)】 30 | 31 | - Movix 这是一个Linux发行版,它基于Knoppix仅仅在CD上运行用来播放电影!你可以创建Movix的CD。它们是可启动的CD,当你重启计算机的时候,放入CD,电影就会自己开始播放!使用Movix观看电影,你甚至不需要硬盘。【[Movix](http://movix.sourceforge.net/)】 32 | 33 | 上面这个列表只是希望给你一个大概的印象——还有很多别的优秀FLOSS,比如Perl语言、PHP语言、Drupal网站内容管理系统、PostgreSQL数据库服务器、TORCS赛车游戏、KDevelop IDE、Anjuta IDE、Xine——电影播放器、VIM编辑器、Quanta+编辑器、XMMS音频播放器、GIMP图像编辑程序……这个列表可以一直继续下去。 34 | 35 | 访问下述网站以获取更多FLOSS信息: 36 | 37 | - [SourceForge](http://www.sourceforge.net/) 38 | 39 | - [FreshMeat](http://www.freshmeat.net/) 40 | 41 | - [KDE](http://www.kde.org/) 42 | 43 | - [GNOME](http://www.gnome.org/) 44 | 45 | 要获知FLOSS世界的最新进展,请访问下述网站: 46 | 47 | - [OSNews](http://www.osnews.com/) 48 | 49 | - [LinuxToday](http://www.linuxtoday.com/) 50 | 51 | - [NewsForge](http://www.newsforge.com/) 52 | 53 | - [SwaroopCH's blog](http://www.swaroopch.info/blog) 54 | 55 | 那么,现在就出发去探索广博、免费、开放的FLOSS世界了吧! -------------------------------------------------------------------------------- /book/第12章 输入&输出.md: -------------------------------------------------------------------------------- 1 | 在很多时候,你会想要让你的程序与用户(可能是你自己)交互。你会从用户那里得到输入,然后打印一些结果。我们可以分别使用raw_input和print语句来完成这些功能。对于输出,你也可以使用多种多样的str(字符串)类。例如,你能够使用rjust方法来得到一个按一定宽度右对齐的字符串。利用help(str)获得更多详情。 2 | 3 | 另一个常用的输入/输出类型是处理文件。创建、读和写文件的能力是许多程序所必需的,我们将会在这章探索如何实现这些功能。 4 | 5 | ## 文件 6 | 你可以通过创建一个file类的对象来打开一个文件,分别使用file类的read、readline或write方法来恰当地读写文件。对文件的读写能力依赖于你在打开文件时指定的模式。最后,当你完成对文件的操作的时候,你调用close方法来告诉Python我们完成了对文件的使用。 7 | 8 | ### 使用文件 9 | **例12.1 使用文件** 10 | 11 | ```python 12 | #!/usr/bin/python 13 | # Filename: using_file.py 14 | 15 | poem = '''\ 16 | Programming is fun 17 | When the work is done 18 | if you wanna make your work also fun: 19 | use Python! 20 | ''' 21 | 22 | f = file('poem.txt', 'w') # open for 'w'riting 23 | f.write(poem) # write text to file 24 | f.close() # close the file 25 | 26 | f = file('poem.txt') 27 | # if no mode is specified, 'r'ead mode is assumed by default 28 | while True: 29 | line = f.readline() 30 | if len(line) == 0: # Zero length indicates EOF 31 | break 32 | print line, 33 | # Notice comma to avoid automatic newline added by Python 34 | f.close() # close the file 35 | ``` 36 | 37 | (源文件:[code/using_file.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_file.py)) 38 | 39 | ### 输出 40 | 41 | ``` 42 | $ python using_file.py 43 | Programming is fun 44 | When the work is done 45 | if you wanna make your work also fun: 46 | use Python! 47 | ``` 48 | 49 | ### 它如何工作 50 | 首先,我们通过指明我们希望打开的文件和模式来创建一个file类的实例。模式可以为读模式('r')、写模式('w')或追加模式('a')。事实上还有多得多的模式可以使用,你可以使用help(file)来了解它们的详情。 51 | 52 | 我们首先用写模式打开文件,然后使用file类的write方法来写文件,最后我们用close关闭这个文件。 53 | 54 | 接下来,我们再一次打开同一个文件来读文件。如果我们没有指定模式,读模式会作为默认的模式。在一个循环中,我们使用readline方法读文件的每一行。这个方法返回包括行末换行符的一个完整行。所以,当一个 空的 字符串被返回的时候,即表示文件末已经到达了,于是我们停止循环。 55 | 56 | 注意,因为从文件读到的内容已经以换行符结尾,所以我们在print语句上使用逗号来消除自动换行。最后,我们用close关闭这个文件。 57 | 58 | 现在,来看一下poem.txt文件的内容来验证程序确实工作正常了。 59 | 60 | ## 储存器 61 | Python提供一个标准的模块,称为pickle。使用它你可以在一个文件中储存任何Python对象,之后你又可以把它完整无缺地取出来。这被称为 持久地 储存对象。 62 | 63 | 还有另一个模块称为cPickle,它的功能和pickle模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle快1000倍)。你可以使用它们中的任一个,而我们在这里将使用cPickle模块。记住,我们把这两个模块都简称为pickle模块。 64 | 65 | ### 储存与取储存 66 | **例12.2 储存与取储存** 67 | 68 | ```python 69 | #!/usr/bin/python 70 | # Filename: pickling.py 71 | 72 | import cPickle as p 73 | #import pickle as p 74 | 75 | shoplistfile = 'shoplist.data' 76 | # the name of the file where we will store the object 77 | 78 | shoplist = ['apple', 'mango', 'carrot'] 79 | 80 | # Write to the file 81 | f = file(shoplistfile, 'w') 82 | p.dump(shoplist, f) # dump the object to a file 83 | f.close() 84 | 85 | del shoplist # remove the shoplist 86 | 87 | # Read back from the storage 88 | f = file(shoplistfile) 89 | storedlist = p.load(f) 90 | print storedlist 91 | ``` 92 | 93 | (源文件:[code/pickling.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/pickling.py)) 94 | 95 | ### 输出 96 | 97 | ``` 98 | $ python pickling.py 99 | ['apple', 'mango', 'carrot'] 100 | ``` 101 | 102 | ### 它如何工作 103 | 首先,请注意我们使用了import..as语法。这是一种便利方法,以便于我们可以使用更短的模块名称。在这个例子中,它还让我们能够通过简单地改变一行就切换到另一个模块(cPickle或者pickle)!在程序的其余部分的时候,我们简单地把这个模块称为p。 104 | 105 | 为了在文件里储存一个对象,首先以写模式打开一个file对象,然后调用储存器模块的dump函数,把对象储存到打开的文件中。这个过程称为 储存 。 106 | 107 | 接下来,我们使用pickle模块的load函数的返回来取回对象。这个过程称为 取储存 。 108 | 109 | ## 概括 110 | 我们已经讨论了多种类型的输入/输出,及文件处理和使用储存器模块。 111 | 112 | 接下来,我们将探索异常的概念。 113 | -------------------------------------------------------------------------------- /book/第16章 接下来学习什么?.md: -------------------------------------------------------------------------------- 1 | 如果你已经完全读完了这本书并且也实践着编写了很多程序,那么你一定已经能够非常熟练自如地使用Python了。你可能也已经编写了一些Python程序来尝试练习各种Python技能和特性。如果你还没有那样做的话,那么你一定要快点去实践。现在的问题是“接下来学习什么?”。 2 | 3 | 我会建议你先解决这样一个问题:创建你自己的命令行 地址簿 程序。在这个程序中,你可以添加、修改、删除和搜索你的联系人(朋友、家人和同事等等)以及它们的信息(诸如电子邮件地址和/或电话号码)。这些详细信息应该被保存下来以便以后提取。 4 | 5 | 思考一下我们到目前为止所学的各种东西的话,你会觉得这个问题其实相当简单。如果你仍然希望知道该从何处入手的话,那么这里也有一个提示。 6 | 7 | 提示(其实你不应该阅读这个提示) 创建一个类来表示一个人的信息。使用字典储存每个人的对象,把他们的名字作为键。使用cPickle模块永久地把这些对象储存在你的硬盘上。使用字典内建的方法添加、删除和修改人员信息。 8 | 9 | 一旦你完成了这个程序,你就可以说是一个Python程序员了。现在,请立即寄一封信给我感谢我为你提供了这本优秀的教材吧。是否告知我,如你所愿,但是我确实希望你能够告诉我。 10 | 11 | 这里有一些继续你的Python之路的方法: 12 | 13 | ## 图形软件 14 | 使用Python的GUI库——你需要使用这些库来用Python语言创建你自己的图形程序。使用GUI库和它们的Python绑定,你可以创建你自己的IrfanView、Kuickshow软件或者任何别的类似的东西。绑定让你能够使用Python语言编写程序,而使用的库本身是用C、C++或者别的语言编写的。 15 | 16 | 有许多可供选择的使用Python的GUI: 17 | 18 | - PyQt 这是Qt工具包的Python绑定。Qt工具包是构建KDE的基石。Qt,特别是配合Qt Designer和出色的Qt文档之后,它极其易用并且功能非常强大。你可以在Linux下免费使用它,但是如果你在Windows下使用它需要付费。使用PyQt,你可以在Linux/Unix上开发免费的(GPL约定的)软件,而开发具产权的软件则需要付费。一个很好的PyQt资源是[《使用Python语言的GUI编程:Qt版》](http://www.opendocs.org/pyqt/)请查阅[官方主页](http://www.riverbankcomputing.co.uk/pyqt/index.php)以获取更多详情。 19 | 20 | - PyGTK 这是GTK+工具包的Python绑定。GTK+工具包是构建GNOME的基石。GTK+在使用上有很多怪癖的地方,不过一旦你习惯了,你可以非常快速地开发GUI应用程序。Glade图形界面设计器是必不可少的,而文档还有待改善。GTK+在Linux上工作得很好,而它的Windows接口还不完整。你可以使用GTK+开发免费和具有产权的软件。请查阅[官方主页](http://www.pygtk.org/)以获取更多详情。 21 | 22 | - wxPython 这是wxWidgets工具包的Python绑定。wxPython有与它相关的学习方法。它的可移植性极佳,可以在Linux、Windows、Mac甚至嵌入式平台上运行。有很多wxPython的IDE,其中包括GUI设计器以及如[SPE(Santi's Python Editor)](http://spe.pycs.net/)和[wxGlade](http://wxglade.sourceforge.net/)那样的GUI开发器。你可以使用wxPython开发免费和具有产权的软件。请查阅[官方主页](http://www.wxpython.org/)以获取更多详情。 23 | 24 | - TkInter 这是现存最老的GUI工具包之一。如果你使用过IDLE,它就是一个TkInter程序。在[PythonWare.org](http://www.pythonware.com/library/tkinter/introduction/index.htm)上的TkInter文档是十分透彻的。TkInter具备可移植性,可以在Linux/Unix和Windows下工作。重要的是,TkInter是标准Python发行版的一部分。 25 | 26 | 要获取更多选择,请参阅[Python.org上的GUI编程wiki页](http://www.python.org/cgi-bin/moinmoin/GuiProgramming)。 27 | 28 | ### GUI工具概括 29 | 不幸的是,并没有单一的标准Python GUI工具。我建议你根据你的情况在上述工具中选择一个。首要考虑的因素是你是否愿意为GUI工具付费。其次考虑的是你是想让你的程序运行在Linux下、Windows下还是两者都要。第三个考虑因素根据你是Linux下的KDE用户还是GNOME用户而定。 30 | 31 | > **未来的章节** 32 | 33 | > 我打算为本书编写一或两个关于GUI编程的章节。我可能会选择wxPython作为工具包。如果你想要表达你对这个主题的意见,请加入[byte-of-python](http://lists.ibiblio.org/mailman/listinfo/byte-of-python)邮件列表。在这个邮件列表中,读者会与我讨论如何改进本书。 34 | 35 | ## 探索更多内容 36 | 37 | - Python标准库是一个丰富的库,在大多数时候,你可以在这个库中找到你所需的东西。这被称为Python的“功能齐全”理念。我强烈建议你在开始开发大型Python程序之前浏览一下[Python标准文档](http://docs.python.org/)。 38 | 39 | - [Python.org](http://www.python.org/)——Python编程语言的官方主页。你可以在上面找到Python语言和解释器的最新版本。另外还有各种邮件列表活跃地讨论Python的各方面内容。 40 | 41 | - comp.lang.python是讨论Python语言的世界性新闻组。你可以把你的疑惑和询问贴在这个新闻组上。可以使用[Google群](http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&group=comp.lang.python)在线访问这个新闻组,或加入作为新闻组镜像的[邮件列表](http://mail.python.org/mailman/listinfo/python-list)。 42 | 43 | - [《Python实用大全》](http://aspn.activestate.com/ASPN/Python/Cookbook/)是一个极有价值的秘诀和技巧集合,它帮助你解决某些使用Python的问题。这是每个Python用户必读的一本书。 44 | 45 | - [《迷人的Python》](http://gnosis.cx/publish/tech_index_cp.html)是David Mertz编著的一系列优秀的Python相关文章。 46 | 47 | - [《深入理解Python》](http://www.diveintopython.org/)是给有经验的Python程序员的一本很优秀的书。如果你已经完整地阅读了本书,那么我强烈建议你接下来阅读《深入理解Python》。它覆盖了包括XML处理、单元测试和功能性编程在内的广泛的主题。 48 | 49 | - [Jython](http://www.jython.org/)是用Java语言实现的Python解释器。这意味着你可以用Python语言编写程序而同时使用Java库!Jython是一个稳定成熟的软件。如果你也是一个Java程序员,我强烈建议你尝试一下Jython。 50 | 51 | - [IronPython](http://www.ironpython.com/)是用C#语言实现的Python解释器,可以运行在.NET、Mono和DotGNU平台上。这意味着你可以用Python语言编写程序而使用.NET库以及其他由这三种平台提供的库!IronPython还只是一个前期alpha测试软件,现在还只适合用来进行试验。Jim Hugunin,IronPython的开发者,已经加入了微软公司,将在将来全力开发一个完整版本的IronPython。 52 | 53 | - [Lython](http://www.caddr.com/code/lython/)是Python语言的Lisp前段。它类似于普通的Lisp语言,会被直接编译为Python字节码,这意味着它能与我们普通的Python代码协同工作。 54 | 55 | - 另外还有很多很多的Python资源。其中比较有趣的有[Daily Python-URL](http://www.pythonware.com/daily/)!,它使你保持与Python的最新进展同步。另外还有[Vaults of Parnassus](http://www.vex.net/parnassus/)、[ONLamp.com Python DevCenter](http://www.onlamp.com/python/)、[dirtSimple.org](http://dirtsimple.org/)、[Python Notes](http://pythonnotes.blogspot.com/)等等。 56 | 57 | ## 概括 58 | 现在,我们已经来到了本书的末尾,但是就如那句名言,这只是 开始的结束 !你现在是一个满怀渴望的Python用户,毫无疑问你准备用Python解决许多问题。你可以使你的计算机自动地完成许多先前无法想象的工作或者编写你自己的游戏,以及更多别的什么东西。所以,请出发吧! 59 | -------------------------------------------------------------------------------- /book/第5章 运算符与表达式.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 你编写的大多数语句(逻辑行)都包含 **表达式** 。一个简单的表达式例子如2 + 3。一个表达式可以分解为运算符和操作数。 3 | 4 | 运算符 的功能是完成某件事,它们由如+这样的符号或者其他特定的关键字表示。运算符需要数据来进行运算,这样的数据被称为 操作数 。在这个例子中,2和3是操作数。 5 | 6 | ## 运算符 7 | 我们将简单浏览一下运算符和它们的用法: 8 | 9 | ### 技巧 10 | 你可以交互地使用解释器来计算例子中给出的表达式。例如,为了测试表达式2 + 3,使用交互式的带提示符的Python解释器: 11 | 12 | ```python 13 | >>> 2 + 3 14 | 5 15 | >>> 3 * 5 16 | 15 17 | >>> 18 | ``` 19 | 20 | **表5.1 运算符与它们的用法** 21 | 22 | 运算符 | 名称 | 说明 | 例子 23 | --- | --- | --- | --- 24 | + | 加 | 两个对象相加 | 3 + 5得到8。'a' + 'b'得到'ab' 25 | - | 减 | 得到负数或是一个数减去另一个数 | -5.2得到一个负数。50 - 24得到26。 26 | * | 幂 | 返回x的y次幂 | 3 ** 4得到81(即3 * 3 * 3 * 3) 27 | / | 除 | x除以y | 4/3得到1(整数的除法得到整数结果)。4.0/3或4/3.0得到1.3333333333333333 28 | // | 取整除 | 返回商的整数部分 | 4 // 3.0得到1.0 29 | % | 取模 | 返回除法的余数 | 8%3得到2。-25.5%2.25得到1.5 30 | << | 左移 | 把一个数的比特向左移一定数目(每个数在内存中都表示为比特或二进制数字,即0和1) | 2 << 2得到8。——2按比特表示为10 31 | >> | 右移 | 把一个数的比特向右移一定数目 | 11 >> 1得到5。——11按比特表示为1011,向右移动1比特后得到101,即十进制的5。 32 | & |按位与 | 数的按位与| 5 & 3得到1。 33 | \| |按位或 | 数的按位或 | 5 | 3得到7。 34 | ^ |按位异或| 数的按位异或| 5 ^ 3得到6 35 | ~ |按位翻转| x的按位翻转是-(x+1)| ~5得到6。 36 | < |小于 |返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。| 5 < 3返回0(即False)而3 < 5返回1(即True)。比较可以被任意连接:3 < 5 < 7返回True。 37 | > |大于 |返回x是否大于y |5 > 3返回True。如果两个操作数都是数字,它们首先被转换为一个共同的类型。否则,它总是返回False。 38 | <= |小于等于 | 返回x是否小于等于y| x = 3; y = 6; x <= y返回True。 39 | >= |大于等于| 返回x是否大于等于y| x = 4; y = 3; x >= y返回True。 40 | == |等于 |比较对象是否相等 |x = 2; y = 2; x == y返回True。x = 'str'; y = 'stR'; x == y返回False。x = 'str'; y = 'str'; x == y返回True。 41 | != |不等于| 比较两个对象是否不相等| x = 2; y = 3; x != y返回True。 42 | not |布尔“非”| 如果x为True,返回False。如果x为False,它返回True。| x = True; not y返回False。 43 | and |布尔“与” |如果x为False,x and y返回False,否则它返回y的计算值。| x = False; y = True; x and y,由于x是False,返回False。在这里,Python不会计算y,因为它知道这个表达式的值肯定是False(因为x是False)。这个现象称为短路计算。 44 | or |布尔“或”| 如果x是True,它返回True,否则它返回y的计算值。| x = True; y = False; x or y返回True。短路计算在这里也适用。 45 | 46 | 47 | 48 | ## 运算符优先级 49 | 如果你有一个如2 + 3 * 4那样的表达式,是先做加法呢,还是先做乘法?我们的中学数学告诉我们应当先做乘法——这意味着乘法运算符的优先级高于加法运算符。 50 | 51 | 下面这个表给出Python的运算符优先级,从最低的优先级(最松散地结合)到最高的优先级(最紧密地结合)。这意味着在一个表达式中,Python会首先计算表中较下面的运算符,然后在计算列在表上部的运算符。 52 | 53 | 下面这张表(与Python参考手册中的那个表一模一样)已经顾及了完整的需要。事实上,我建议你使用圆括号来分组运算符和操作数,以便能够明确地指出运算的先后顺序,使程序尽可能地易读。例如,2 + (3 * 4)显然比2 + 3 * 4清晰。与此同时,圆括号也应该正确使用,而不应该用得过滥(比如2 + (3 + 4))。 54 | 55 | **表5.2 运算符优先级** 56 | 57 | 58 | 运算符 | 描述 59 | --- | --- 60 | lambda |Lambda表达式 61 | or |布尔“或” 62 | and |布尔“与” 63 | not x |布尔“非” 64 | in,not in |成员测试 65 | is,is not |同一性测试 66 | <,<=,>,>=,!=,== |比较 67 | `|` |按位或 68 | ^ |按位异或 69 | & |按位与 70 | <<,>> |移位 71 | +,- |加法与减法 72 | *,/,% |乘法、除法与取余 73 | +x,-x |正负号 74 | ~x |按位翻转 75 | ** |指数 76 | x.attribute | 属性参考 77 | x[index] | 下标 78 | x[index:index] | 寻址段 79 | f(arguments...) | 函数调用 80 | (experession,...) | 绑定或元组显示 81 | [expression,...] | 列表显示 82 | {key:datum,...} | 字典显示 83 | 'expression,...' | 字符串转换 84 | 85 | 其中我们还没有接触过的运算符将在后面的章节中介绍。 86 | 87 | 在表中列在同一行的运算符具有 相同优先级 。例如,+和-有相同的优先级。 88 | 89 | ### 计算顺序 90 | 默认地,运算符优先级表决定了哪个运算符在别的运算符之前计算。然而,如果你想要改变它们的计算顺序,你得使用圆括号。例如,你想要在一个表达式中让加法在乘法之前计算,那么你就得写成类似(2 + 3) * 4的样子。 91 | ### 结合规律 92 | 运算符通常由左向右结合,即具有相同优先级的运算符按照从左向右的顺序计算。例如,2 + 3 + 4被计算成(2 + 3) + 4。一些如赋值运算符那样的运算符是由右向左结合的,即a = b = c被处理为a = (b = c)。 93 | 94 | ## 表达式 95 | 96 | ### 使用表达式 97 | **例5.1 使用表达式** 98 | 99 | ```python 100 | #!/usr/bin/python 101 | # Filename: expression.py 102 | 103 | length = 5 104 | breadth = 2 105 | area = length * breadth 106 | print 'Area is', area 107 | print 'Perimeter is', 2 * (length + breadth) 108 | ``` 109 | 110 | (源文件: [code/expression.py][ref_Code]) 111 | 112 | ### 输出 113 | 114 | ``` 115 | $ python expression.py 116 | Area is 10 117 | Perimeter is 14 118 | ``` 119 | 120 | ### 它如何工作 121 | 矩形的长度与宽度存储在以它们命名的变量中。我们借助表达式使用它们计算矩形的面积和边长。我们表达式length * breadth的结果存储在变量area中,然后用print语句打印。在另一个打印语句中,我们直接使用表达式2 * (length + breadth)的值。 122 | 123 | 另外,注意Python如何打印“漂亮的”输出。尽管我们没有在'Area is'和变量area之间指定空格,Python自动在那里放了一个空格,这样我们就可以得到一个清晰漂亮的输出,而程序也变得更加易读(因为我们不需要担心输出之间的空格问题)。这是Python如何使程序员的生活变得更加轻松的一个例子。 124 | 125 | ## 概括 126 | 我们已经学习了如何使用运算符、操作数和表达式——这些使任何程序的基本组成部分。接下来,我们将学习如何通过语句在我们的程序中使用这些部分。 127 | 128 | [ref_Code]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/expression.py 129 | -------------------------------------------------------------------------------- /book/第1章 介绍.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | Python语言是少有的一种可以称得上即 **简单** 又 **功能强大** 的编程语言。你将惊喜地发现Python语言是多么地简单,它注重的是如何解决问题而不是编程语言的语法和结构。 3 | 4 | Python的官方介绍是: 5 | > Python是一种简单易学,功能强大的编程语言,它有高效率的高层数据结构,简单而有效地实现面向对象编程。Python简洁的语法和对动态输入的支持,再加上解释性语言的本质,使得它在大多数平台上的许多领域都是一个理想的脚本语言,特别适用于快速的应用程序开发。 6 | 7 | 我会在下一节里详细地讨论Python的这些特点。 8 | 9 | 10 | > **注释** 11 | 12 | > Python语言的创造者Guido van Rossum是根据英国广播公司的节目“蟒蛇飞行马戏”命名这个语言的,并非他本人特别喜欢蛇缠起它们的长身躯碾死动物觅食。 13 | 14 | 15 | ## Python的特色 16 | 17 | ### 简单 18 | Python是一种代表简单主义思想的语言。阅读一个良好的Python程序就感觉像是在读英语一样,尽管这个英语的要求非常严格!Python的这种伪代码本质是它最大的优点之一。它使你能够专注于解决问题而不是去搞明白语言本身。 19 | 20 | ### 易学 21 | 就如同你即将看到的一样,Python极其容易上手。前面已经提到了,Python有极其简单的语法。 22 | 23 | ### 免费、开源 24 | Python是FLOSS(自由/开放源码软件)之一。简单地说,你可以自由地发布这个软件的拷贝、阅读它的源代码、对它做改动、把它的一部分用于新的自由软件中。FLOSS是基于一个团体分享知识的概念。这是为什么Python如此优秀的原因之一——它是由一群希望看到一个更加优秀的Python的人创造并经常改进着的。 25 | 26 | ### 高层语言 27 | 当你用Python语言编写程序的时候,你无需考虑诸如如何管理你的程序使用的内存一类的底层细节。 28 | 29 | ### 可移植性 30 | 由于它的开源本质,Python已经被移植在许多平台上(经过改动使它能够工作在不同平台上)。如果你小心地避免使用依赖于系统的特性,那么你的所有Python程序无需修改就可以在下述任何平台上面运行。 31 | 32 | 这些平台包括Linux、Windows、FreeBSD、Macintosh、Solaris、OS/2、Amiga、AROS、AS/400、BeOS、OS/390、z/OS、Palm OS、QNX、VMS、Psion、Acom RISC OS、VxWorks、PlayStation、Sharp Zaurus、Windows CE甚至还有PocketPC! 33 | 34 | ### 解释性 35 | 这一点需要一些解释。 36 | 37 | 一个用编译性语言比如C或C++写的程序可以从源文件(即C或C++语言)转换到一个你的计算机使用的语言(二进制代码,即0和1)。这个过程通过编译器和不同的标记、选项完成。当你运行你的程序的时候,连接/转载器软件把你的程序从硬盘复制到内存中并且运行。 38 | 39 | 而Python语言写的程序不需要编译成二进制代码。你可以直接从源代码 运行 程序。在计算机内部,Python解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。事实上,由于你不再需要担心如何编译程序,如何确保连接转载正确的库等等,所有这一切使得使用Python更加简单。由于你只需要把你的Python程序拷贝到另外一台计算机上,它就可以工作了,这也使得你的Python程序更加易于移植。 40 | 41 | ### 面向对象 42 | Python即支持面向过程的编程也支持面向对象的编程。在 **面向过程** 的语言中,程序是由过程或仅仅是可重用代码的函数构建起来的。在 **面向对象** 的语言中,程序是由数据和功能组合而成的对象构建起来的。与其他主要的语言如C++和Java相比,Python以一种非常强大又简单的方式实现面向对象编程。 43 | 44 | ### 可扩展性 45 | 如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们。 46 | 47 | ### 可嵌入性 48 | 你可以把Python嵌入你的C/C++程序,从而向你的程序用户提供脚本功能。 49 | 50 | ### 丰富的库 51 | Python标准库确实很庞大。它可以帮助你处理各种工作,包括正则表达式、文档生成、单元测试、线程、数据库、网页浏览器、CGI、FTP、电子邮件、XML、XML-RPC、HTML、WAV文件、密码系统、GUI(图形用户界面)、Tk和其他与系统有关的操作。记住,只要安装了Python,所有这些功能都是可用的。这被称作Python的“功能齐全”理念。 52 | 53 | 除了标准库以外,还有许多其他高质量的库,如[wxPython][ref_wxPython]、[Twisted][ref_Twisted]和[Python图像库][ref_Python图像库]等等。 54 | 55 | ### 概括 56 | Python确实是一种十分精彩又强大的语言。它合理地结合了高性能与使得编写程序简单有趣的特色。 57 | 58 | ## 为什么不使用Perl? 59 | 也许你以前并不知道,Perl是另外一种极其流行的开源解释性编程语言。 60 | 61 | 如果你曾经尝试过用Perl语言编写一个大程序,你一定会自己回答这个问题。在规模较小的时候,Perl程序是简单的。它可以胜任于小型的应用程序和脚本,“使工作完成”。然而,当你想开始写一些大一点的程序的时候,Perl程序就变得不实用了。我是通过为Yahoo编写大型Perl程序的经验得出这样的总结的! 62 | 63 | 与Perl相比,Python程序一定会更简单、更清晰、更易于编写,从而也更加易懂、易维护。我确实也很喜欢Perl,用它来做一些日常的各种事情。不过当我要写一个程序的时候,我总是想到使用Python,这对我来说已经成了十分自然的事。Perl已经经历了多次大的修正和改变,遗憾的是,即将发布的Perl 6似乎仍然没有在这个方面做什么改进。 64 | 65 | 我感到Perl唯一也是十分重要的优势是它庞大的[CPAN][ref_CPAN]库——综合Perl存档网络。就如同这个名字所指的意思一样,这是一个巨大的Perl模块集,它大得让人难以置信——你几乎用这些模块在计算机上做任何事情。Perl的模块比Python多的原因之一是Perl拥有更加悠久的历史。或许我会在[comp.lang.python][ref_CLP]上建议把Perl模块移植到Python上的计划。 66 | 67 | 另外,新的[Parrot虚拟机][ref_Parrot]按设计可以运行完全重新设计的Perl 6也可以运行Python和其他解释性语言如Ruby、PHP和Tcl等等。这意味着你将来 或许 可以在Python上使用所有Perl的模块。这将成为两全其美的事——强大的CPAN库与强大的Python语言结合在一起。我们将拭目以待。 68 | 69 | ## 程序员的话 70 | 读一下像ESR这样的超级电脑高手谈Python的话,你会感到十分有意思: 71 | > **Eric S. Raymond**是《The Cathedral and the Bazaar》的作者、“开放源码”一词的提出人。他说[Python已经成为了他最喜爱的编程语言][ref_favorite]。这篇文章也是促使我第一次接触Python的真正原动力。 72 | 73 | 74 | > **Bruce Eckel**著名的《Thinking in Java》和《Thinking in C++》的作者。他说没有一种语言比得上Python使他的工作效率如此之高。同时他说Python可能是唯一一种旨在帮助程序员把事情弄得更加简单的语言。请阅读[完整的采访][ref_views]以获得更详细的内容。 75 | 76 | 77 | > **Peter Norvig**是著名的Lisp语言书籍的作者和Google公司的搜索质量主任(感谢Guido van Rossum告诉我这一点)。他说Python始终是Google的主要部分。事实上你看一下[Google招聘][ref_GoogleJob]的网页就可以验证这一点。在那个网页上,Python知识是对软件工程师的一个必需要求。 78 | 79 | 80 | > **Bruce Perens**是OpenSource.org和UserLinux项目的一位共同创始人。UserLinux旨在创造一个可以被多家发行商支持标准的Linux发行版。Python击败了其它竞争对手如Perl和Ruby成为UserLinux支持的主要编程语言。 81 | 82 | [ref_wxPython]: http://www.wxpython.org/ 83 | [ref_Twisted]: http://www.twistedmatrix.com/products/twisted 84 | [ref_Python图像库]: http://www.pythonware.com/products/pil/index.htm 85 | [ref_CPAN]: http://cpan.perl.org/ 86 | [ref_CLP]: https://groups.google.com/groups?q=comp.lang.python 87 | [ref_Parrot]: http://www.parrot.org/ 88 | [ref_favorite]: http://www.linuxjournal.com/article/3882 89 | [ref_views]: http://www.artima.com/inv/aboutme.html 90 | [ref_GoogleJob]: http://www.google.com/about/jobs/ -------------------------------------------------------------------------------- /book/第14章 Python标准库.md: -------------------------------------------------------------------------------- 1 | ## 第14章 Python标准库 2 | Python标准库是随Python附带安装的,它包含大量极其有用的模块。熟悉Python标准库是十分重要的,因为如果你熟悉这些库中的模块,那么你的大多数问题都可以简单快捷地使用它们来解决。 3 | 4 | 我们已经研究了一些这个库中的常用模块。你可以在Python附带安装的文档的“库参考”一节中了解Python标准库中所有模块的完整内容。 5 | 6 | ## sys模块 7 | sys模块包含系统对应的功能。我们已经学习了sys.argv列表,它包含命令行参数。 8 | 9 | ### 命令行参数 10 | **例14.1 使用sys.argv** 11 | 12 | ```python 13 | #!/usr/bin/python 14 | # Filename: cat.py 15 | 16 | import sys 17 | 18 | def readfile(filename): 19 | '''Print a file to the standard output.''' 20 | f = file(filename) 21 | while True: 22 | line = f.readline() 23 | if len(line) == 0: 24 | break 25 | print line, # notice comma 26 | f.close() 27 | 28 | # Script starts from here 29 | if len(sys.argv) < 2: 30 | print 'No action specified.' 31 | sys.exit() 32 | 33 | if sys.argv[1].startswith('--'): 34 | option = sys.argv[1][2:] 35 | # fetch sys.argv[1] but without the first two characters 36 | if option == 'version': 37 | print 'Version 1.2' 38 | elif option == 'help': 39 | print '''\ 40 | This program prints files to the standard output. 41 | Any number of files can be specified. 42 | Options include: 43 | --version : Prints the version number 44 | --help : Display this help''' 45 | else: 46 | print 'Unknown option.' 47 | sys.exit() 48 | else: 49 | for filename in sys.argv[1:]: 50 | readfile(filename) 51 | ``` 52 | 53 | (源文件:[code/cat.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/cat.py)) 54 | 55 | ### 输出 56 | 57 | ``` 58 | $ python cat.py 59 | No action specified. 60 | 61 | $ python cat.py --help 62 | This program prints files to the standard output. 63 | Any number of files can be specified. 64 | Options include: 65 | --version : Prints the version number 66 | --help : Display this help 67 | 68 | $ python cat.py --version 69 | Version 1.2 70 | 71 | $ python cat.py --nonsense 72 | Unknown option. 73 | 74 | $ python cat.py poem.txt 75 | Programming is fun 76 | When the work is done 77 | if you wanna make your work also fun: 78 | use Python! 79 | ``` 80 | 81 | ### 它如何工作 82 | 这个程序用来模范Linux/Unix用户熟悉的cat命令。你只需要指明某些文本文件的名字,这个程序会把它们打印输出。 83 | 84 | 在Python程序运行的时候,即不是在交互模式下,在sys.argv列表中总是至少有一个项目。它就是当前运行的程序名称,作为sys.argv[0](由于Python从0开始计数)。其他的命令行参数在这个项目之后。 85 | 86 | 为了使这个程序对用户更加友好,我们提供了一些用户可以指定的选项来了解更多程序的内容。我们使用第一个参数来检验我们的程序是否被指定了选项。如果使用了--version选项,程序的版本号将被打印出来。类似地,如果指定了--help选项,我们提供一些关于程序的解释。我们使用sys.exit函数退出正在运行的程序。和以往一样,你可以看一下help(sys.exit)来了解更多详情。 87 | 88 | 如果没有指定任何选项,而是为程序提供文件名的话,它就简单地打印出每个文件地每一行,按照命令行中的顺序一个文件接着一个文件地打印。 89 | 90 | 顺便说一下,名称cat是 concatenate 的缩写,它基本上表明了程序的功能——它可以在输出打印一个文件或者把两个或两个以上文件连接/级连在一起打印。 91 | 92 | ### 更多sys的内容 93 | sys.version字符串给你提供安装的Python的版本信息。sys.version_info元组则提供一个更简单的方法来使你的程序具备Python版本要求功能。 94 | 95 | ``` 96 | [swaroop@localhost code]$ python 97 | >>> import sys 98 | >>> sys.version 99 | '2.3.4 (#1, Oct 26 2004, 16:42:40) \n[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]' 100 | >>> sys.version_info 101 | (2, 3, 4, 'final', 0) 102 | ``` 103 | 104 | 对于有经验的程序员,sys模块中其他令人感兴趣的项目有sys.stdin、sys.stdout和sys.stderr它们分别对应你的程序的标准输入、标准输出和标准错误流。 105 | 106 | ## os模块 107 | 这个模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。一个例子就是使用os.sep可以取代操作系统特定的路径分割符。 108 | 109 | 下面列出了一些在os模块中比较有用的部分。它们中的大多数都简单明了。 110 | 111 | - os.name字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。 112 | - os.getcwd()函数得到当前工作目录,即当前Python脚本工作的目录路径。 113 | - os.getenv()和os.putenv()函数分别用来读取和设置环境变量。 114 | - os.listdir()返回指定目录下的所有文件和目录名。 115 | - os.remove()函数用来删除一个文件。 116 | - os.system()函数用来运行shell命令。 117 | - os.linesep字符串给出当前平台使用的行终止符。例如,Windows使用'\r\n',Linux使用'\n'而Mac使用'\r'。 118 | - os.path.split()函数返回一个路径的目录名和文件名。 119 | 120 | ``` 121 | >>> os.path.split('/home/swaroop/byte/code/poem.txt') 122 | ('/home/swaroop/byte/code', 'poem.txt') 123 | ``` 124 | 125 | - os.path.isfile()和os.path.isdir()函数分别检验给出的路径是一个文件还是目录。类似地,os.path.existe()函数用来检验给出的路径是否真地存在。 126 | 127 | 你可以利用Python标准文档去探索更多有关这些函数和变量的详细知识。你也可以使用help(sys)等等。 128 | 129 | ## 概括 130 | 我们已经学习了Python标准库中的sys模块和os模块的一部分功能。你应该利用Python标准文档去学习这两个模块以及其他模块的更多内容。 131 | 132 | 接下来,我们将要学习Python中剩余的几个方面的内容,从而使我们的Python课程更加 完整 。 133 | 134 | -------------------------------------------------------------------------------- /book/第15章 更多Python的内容.md: -------------------------------------------------------------------------------- 1 | 到目前为止,我们已经学习了绝大多数常用的Python知识。在这一章中,我们将要学习另外一些方面的Python知识,从而使我们对Python的了解更加 完整 。 2 | 3 | ## 特殊的方法 4 | 在类中有一些特殊的方法具有特殊的意义,比如__init__和__del__方法,它们的重要性我们已经学习过了。 5 | 6 | 一般说来,特殊的方法都被用来模仿某个行为。例如,如果你想要为你的类使用x[key]这样的索引操作(就像列表和元组一样),那么你只需要实现__getitem__()方法就可以了。想一下,Python就是对list类这样做的! 7 | 8 | 下面这个表中列出了一些有用的特殊方法。如果你想要知道所有的特殊方法,你可以在《Python参考手册》中找到一个庞大的列表 9 | 10 | **表15.1 一些特殊的方法** 11 | 12 | 名称 | 说明 13 | --- | --- 14 | \__init__(self,...) | 这个方法在新建对象恰好要被返回使用之前被调用。 15 | \__del__(self) | 恰好在对象要被删除之前调用。 16 | \__str__(self) | 在我们对对象使用print语句或是使用str()的时候调用。 17 | \__lt__(self,other) | 当使用 小于 运算符(<)的时候调用。类似地,对于所有的运算符(+,>等等)都有特殊的方法。 18 | \__getitem__(self,key) | 使用x[key]索引操作符的时候调用。 19 | \__len__(self) | 对序列对象使用内建的len()函数的时候调用。 20 | 21 | ## 单语句块 22 | 现在,你已经很深刻地理解了每一个语句块是通过它的缩进层次与其它块区分开来的。然而这在大多数情况下是正确的,但是并非100%的准确。如果你的语句块只包含一句语句,那么你可以在条件语句或循环语句的同一行指明它。下面这个例子清晰地说明了这一点: 23 | 24 | ``` 25 | >>> flag = True 26 | >>> if flag: print 'Yes' 27 | ... 28 | Yes 29 | ``` 30 | 31 | 就如你所看见的,单个语句被直接使用而不是作为一个独立的块使用。虽然这样做可以使你的程序变得 小一些 ,但是除了检验错误之外我强烈建议你不要使用这种缩略方法。不使用它的一个主要的理由是一旦你使用了恰当的缩进,你就可以很方便地添加一个额外的语句。 32 | 33 | 另外,注意在使用交互模式的Python解释器的时候,它会通过恰当地改变提示符来帮助你输入语句。在上面这个例子中,当你输入了关键字if之后,Python解释器把提示符改变为...以表示语句还没有结束。在这种情况下,我们按回车键用来确认语句已经完整了。然后,Python完成整个语句的执行,并且返回原来的提示符并且等待下一句输入。 34 | 35 | ## 列表综合 36 | 通过列表综合,可以从一个已有的列表导出一个新的列表。例如,你有一个数的列表,而你想要得到一个对应的列表,使其中所有大于2的数都是原来的2倍。对于这种应用,列表综合是最理想的方法。 37 | 38 | ### 使用列表综合 39 | **例15.1 使用列表综合** 40 | 41 | ```python 42 | #!/usr/bin/python 43 | # Filename: list_comprehension.py 44 | 45 | listone = [2, 3, 4] 46 | listtwo = [2*i for i in listone if i > 2] 47 | print listtwo 48 | ``` 49 | 50 | (源文件:[code/list_comprehension.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/list_comprehension.py)) 51 | 52 | ### 输出 53 | 54 | ``` 55 | $ python list_comprehension.py 56 | [6, 8] 57 | ``` 58 | 59 | ### 它如何工作 60 | 这里我们为满足条件(if i > 2)的数指定了一个操作(2*i),从而导出一个新的列表。注意原来的列表并没有发生变化。在很多时候,我们都是使用循环来处理列表中的每一个元素,而使用列表综合可以用一种更加精确、简洁、清楚的方法完成相同的工作。 61 | 62 | ## 在函数中接收元组和列表 63 | 当要使函数接收元组或字典形式的参数的时候,有一种特殊的方法,它分别使用*和**前缀。这种方法在函数需要获取可变数量的参数的时候特别有用。 64 | 65 | ``` 66 | >>> def powersum(power, *args): 67 | ... '''Return the sum of each argument raised to specified power.''' 68 | ... total = 0 69 | ... for i in args: 70 | ... total += pow(i, power) 71 | ... return total 72 | ... 73 | >>> powersum(2, 3, 4) 74 | 25 75 | 76 | >>> powersum(2, 10) 77 | 100 78 | ``` 79 | 80 | 由于在args变量前有*前缀,所有多余的函数参数都会作为一个元组存储在args中。如果使用的是**前缀,多余的参数则会被认为是一个字典的键/值对。 81 | 82 | ## lambda形式 83 | lambda语句被用来创建新的函数对象,并且在运行时返回它们。 84 | **例15.2 使用lambda形式** 85 | 86 | ```python 87 | #!/usr/bin/python 88 | # Filename: lambda.py 89 | 90 | def make_repeater(n): 91 | return lambda s: s*n 92 | 93 | twice = make_repeater(2) 94 | 95 | print twice('word') 96 | print twice(5) 97 | ``` 98 | 99 | (源文件:[code/lambda.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/lambda.py)) 100 | 101 | ### 输出 102 | 103 | ``` 104 | $ python lambda.py 105 | wordword 106 | 10 107 | ``` 108 | 109 | ### 它如何工作 110 | 这里,我们使用了make_repeater函数在运行时创建新的函数对象,并且返回它。lambda语句用来创建函数对象。本质上,lambda需要一个参数,后面仅跟单个表达式作为函数体,而表达式的值被这个新建的函数返回。注意,即便是print语句也不能用在lambda形式中,只能使用表达式。 111 | 112 | ## exec和eval语句 113 | exec语句用来执行储存在字符串或文件中的Python语句。例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。下面是一个简单的例子。 114 | 115 | ``` 116 | >>> exec 'print "Hello World"' 117 | Hello World 118 | ``` 119 | 120 | eval语句用来计算存储在字符串中的有效Python表达式。下面是一个简单的例子。 121 | 122 | ``` 123 | >>> eval('2*3') 124 | 6 125 | ``` 126 | 127 | ## assert语句 128 | assert语句用来声明某个条件是真的。例如,如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一个AssertionError。 129 | 130 | 131 | ``` 132 | >>> mylist = ['item'] 133 | >>> assert len(mylist) >= 1 134 | >>> mylist.pop() 135 | 'item' 136 | >>> assert len(mylist) >= 1 137 | Traceback (most recent call last): 138 | File "", line 1, in ? 139 | AssertionError 140 | ``` 141 | 142 | ## repr函数 143 | repr函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。注意,在大多数时候有eval(repr(object)) == object。 144 | 145 | ``` 146 | >>> i = [] 147 | >>> i.append('item') 148 | >>> `i` 149 | "['item']" 150 | >>> repr(i) 151 | "['item']" 152 | ``` 153 | 154 | 基本上,repr函数和反引号用来获取对象的可打印的表示形式。你可以通过定义类的__repr__方法来控制你的对象在被repr函数调用的时候返回的内容。 155 | 156 | ## 概括 157 | 在这一章中,我们又学习了一些Python的特色,然而你可以肯定我们并没有学习完Python的所有特色。不过,到目前为止,我们确实已经学习了绝大多数你在实际中会使用的内容。这些已经足以让你去创建任何程序了。 158 | 159 | 接下来,我们会讨论一下如何进一步深入探索Python。 -------------------------------------------------------------------------------- /book/第13章 异常.md: -------------------------------------------------------------------------------- 1 | 当你的程序中出现某些 异常的 状况的时候,异常就发生了。例如,当你想要读某个文件的时候,而那个文件不存在。或者在程序运行的时候,你不小心把它删除了。上述这些情况可以使用异常来处理。 2 | 3 | 假如你的程序中有一些无效的语句,会怎么样呢?Python会引发并告诉你那里有一个错误,从而处理这样的情况。 4 | 5 | ## 错误 6 | 考虑一个简单的print语句。假如我们把print误拼为Print,注意大写,这样Python会 引发 一个语法错误。 7 | 8 | ``` 9 | >>> Print 'Hello World' 10 | File "", line 1 11 | Print 'Hello World' 12 | ^ 13 | SyntaxError: invalid syntax 14 | 15 | >>> print 'Hello World' 16 | Hello World 17 | ``` 18 | 19 | 我们可以观察到有一个SyntaxError被引发,并且检测到的错误位置也被打印了出来。这是这个错误的 错误处理器 所做的工作。 20 | 21 | ## try..except 22 | 我们尝试读取用户的一段输入。按Ctrl-d,看一下会发生什么。 23 | 24 | ``` 25 | >>> s = raw_input('Enter something --> ') 26 | Enter something --> Traceback (most recent call last): 27 | File "", line 1, in ? 28 | EOFError 29 | ``` 30 | 31 | Python引发了一个称为EOFError的错误,这个错误基本上意味着它发现一个不期望的 文件尾 (由Ctrl-d表示) 32 | 33 | 接下来,我们将学习如何处理这样的错误。 34 | 35 | ### 处理异常 36 | 我们可以使用try..except语句来处理异常。我们把通常的语句放在try-块中,而把我们的错误处理语句放在except-块中。 37 | 38 | **例13.1 处理异常** 39 | 40 | ```python 41 | #!/usr/bin/python 42 | # Filename: try_except.py 43 | 44 | import sys 45 | 46 | try: 47 | s = raw_input('Enter something --> ') 48 | except EOFError: 49 | print '\nWhy did you do an EOF on me?' 50 | sys.exit() # exit the program 51 | except: 52 | print '\nSome error/exception occurred.' 53 | # here, we are not exiting the program 54 | 55 | print 'Done' 56 | ``` 57 | 58 | (源文件:[code/try_except.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/try_except.py)) 59 | 60 | ### 输出 61 | 62 | ``` 63 | $ python try_except.py 64 | Enter something --> 65 | Why did you do an EOF on me? 66 | 67 | $ python try_except.py 68 | Enter something --> Python is exceptional! 69 | Done 70 | ``` 71 | 72 | ### 它如何工作 73 | 74 | 我们把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个try从句,至少都有一个相关联的except从句。 75 | 76 | 如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并且打印一个消息,我们已经看到了这样的处理。 77 | 78 | 你还可以让try..catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。 79 | 80 | 我们还可以得到异常对象,从而获取更多有个这个异常的信息。这会在下一个例子中说明。 81 | 82 | 我们把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个try从句,至少都有一个相关联的except从句。 83 | 84 | 如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并且打印一个消息,我们已经看到了这样的处理。 85 | 86 | 你还可以让try..catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。 87 | 88 | 我们还可以得到异常对象,从而获取更多有个这个异常的信息。这会在下一个例子中说明。 89 | 90 | ## 引发异常 91 | 92 | 你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。 93 | 94 | ### 如何引发异常 95 | **例13.2 如何引发异常** 96 | 97 | ```python 98 | #!/usr/bin/python 99 | # Filename: raising.py 100 | 101 | class ShortInputException(Exception): 102 | '''A user-defined exception class.''' 103 | def __init__(self, length, atleast): 104 | Exception.__init__(self) 105 | self.length = length 106 | self.atleast = atleast 107 | 108 | try: 109 | s = raw_input('Enter something --> ') 110 | if len(s) < 3: 111 | raise ShortInputException(len(s), 3) 112 | # Other work can continue as usual here 113 | except EOFError: 114 | print '\nWhy did you do an EOF on me?' 115 | except ShortInputException, x: 116 | print 'ShortInputException: The input was of length %d, \ 117 | was expecting at least %d' % (x.length, x.atleast) 118 | else: 119 | print 'No exception was raised.' 120 | ``` 121 | 122 | 源文件([code/raising.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/raising.py)) 123 | 124 | ### 输出 125 | 126 | ``` 127 | $ python raising.py 128 | Enter something --> 129 | Why did you do an EOF on me? 130 | 131 | $ python raising.py 132 | Enter something --> ab 133 | ShortInputException: The input was of length 2, was expecting at least 3 134 | 135 | $ python raising.py 136 | Enter something --> abc 137 | No exception was raised. 138 | ``` 139 | 140 | ### 它如何工作 141 | 142 | 这里,我们创建了我们自己的异常类型,其实我们可以使用任何预定义的异常/错误。这个新的异常类型是ShortInputException类。它有两个域——length是给定输入的长度,atleast则是程序期望的最小长度。 143 | 144 | 在except从句中,我们提供了错误类和用来表示错误/异常对象的变量。这与函数调用中的形参和实参概念类似。在这个特别的except从句中,我们使用异常对象的length和atleast域来为用户打印一个恰当的消息。 145 | 146 | ## try..finally 147 | 假如你在读一个文件的时候,希望在无论异常发生与否的情况下都关闭文件,该怎么做呢?这可以使用finally块来完成。注意,在一个try块下,你可以同时使用except从句和finally块。如果你要同时使用它们的话,需要把一个嵌入另外一个。 148 | 149 | ### 使用finally 150 | **例13.3 使用finally** 151 | 152 | ```python 153 | #!/usr/bin/python 154 | # Filename: finally.py 155 | 156 | import time 157 | 158 | try: 159 | f = file('poem.txt') 160 | while True: # our usual file-reading idiom 161 | line = f.readline() 162 | if len(line) == 0: 163 | break 164 | time.sleep(2) 165 | print line, 166 | finally: 167 | f.close() 168 | print 'Cleaning up...closed the file' 169 | ``` 170 | 171 | (源文件:[code/finally.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/finally.py)) 172 | 173 | ### 输出 174 | 175 | ``` 176 | $ python finally.py 177 | Programming is fun 178 | When the work is done 179 | Cleaning up...closed the file 180 | Traceback (most recent call last): 181 | File "finally.py", line 12, in ? 182 | time.sleep(2) 183 | KeyboardInterrupt 184 | ``` 185 | 186 | ### 它如何工作 187 | 我们进行通常的读文件工作,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些(Python由于其本质通常运行得很快)。在程序运行的时候,按Ctrl-c中断/取消程序。 188 | 189 | 我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭 190 | 191 | ## 概括 192 | 我们已经讨论了try..except和try..finally语句的用法。我们还学习了如何创建我们自己的异常类型和如何引发异常。 193 | 194 | 接下来,我们将探索Python标准库。 -------------------------------------------------------------------------------- /book/第3章 最初的步骤.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 我们将看一下如何用Python编写运行一个传统的 `Hello World` 程序。通过它,你将学会如何编写、保存和运行Python程序。 3 | 4 | 有两种使用Python运行你的程序的方式——使用交互式的带提示符的解释器或使用源文件。我们将学习这两种方法。 5 | 6 | ## 使用带提示符的解释器 7 | 在命令行的shell提示符下键入 **python** ,启动解释器。现在输入 `print 'Hello World'` ,然后按Enter键。你应该可以看到输出的单词Hello World。 8 | 9 | 对于Windows用户,只要你正确的设置了PATH变量,你应该可以从命令行启动解释器。或者你可以选择使用IDLE程序。IDLE是集成开发环境的缩写。点击开始->程序->Python 2.3->IDLE(Python GUI)。Linux用户也可以使用IDLE。 10 | 11 | 注意, `>>>` 是你键入Python语句的提示符。 12 | 13 | **例3.1 使用带提示符的Python解释器** 14 | 15 | ```python 16 | $ python 17 | Python 2.3.4 (#1, Oct 26 2004, 16:42:40) 18 | [GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2 19 | Type "help", "copyright", "credits" or "license" for more information. 20 | >>> print 'hello world' 21 | hello world 22 | >>> 23 | ``` 24 | 25 | 注意,Python会在下一行立即给出你输出!你刚才键入的是一句Python 语句 。我们使用 `print` (不要惊讶)来打印你提供给它的值。这里,我们提供的是文本Hello World,它被迅速地打印在屏幕上。 26 | 27 | > **如何退出Python提示符** 28 | 29 | > 如果你使用的是Linux/BSD shell,那么按Ctrl-d退出提示符。如果是在Windows命令行中,则按Ctrl-z再按Enter。 30 | 31 | ## 挑选一个编辑器 32 | 在我们开始讲述以源文件方式编写Python程序之前,我们需要一个编辑器来写源文件。挑选一个编辑器确实是极其重要的。你挑选一个编辑器就如同你挑选一辆你将购买的轿车一样。一个好的编辑器会帮助你方便地编写Python程序,使你地编程旅程更加舒适,帮助你更加快捷安全地到达目的地(实现目标)。 33 | 34 | 对于编辑器的基本要求之一是 **语法加亮** 功能,利用这一功能,你的Python程序的不同部分被标以不同的颜色,这样你可以更好 **看清楚** 你的程序,使它的运行显得形象化。 35 | 36 | 如果你使用Windows,那么我建议你使用IDLE。IDLE具备语法加亮功能,还有许多其他的功能,比如允许你在IDLE中运行你的程序。特别值得注意的是: **不要使用Notepad** ——它是一个糟糕的选择,因为它没有语法加亮功能,而且更加重要的是,它不支持文本缩进。而我们将会看到文本缩进对于我们来说极其重要。一个好的编辑器,比如IDLE(还有VIM)将会自动帮助你做这些事情。 37 | 38 | 如果你使用Linux/FreeBSD,那么你有很多种选择。如果你是一位有经验的程序员,你一定已经在使用VIM或者Emacs了。勿庸置疑,它们是两个功能最强大的编辑器。使用它们编写你的Python程序,你将从中受益。我个人使用VIM编写我的大多数程序。如果你是一个初学编程的人,那么你可以使用Kate,它也是我最喜欢的编辑器之一。只要你愿意花时间学习使用VIM或Emacs,那么我强烈建议你一定要学习两者之一,因为从长远看来它们对你是极其有帮助的。 39 | 40 | 如果你还想寻找一下其他可供选择的编辑器,可以看一下详尽的[Python编辑器列表][ref_edit_list],然后作出你的选择。你也可以使用Python的IDE(集成开发环境)。请看一下详尽的[支持Python的IDE列表][ref_IDE_list]以获得详尽的信息。一旦你开始编写大型的Python程序,IDE确实很有用。 41 | 42 | 我再一次重申,请选择一个合适的编辑器——它能使编写Python程序变得更加有趣、方便。 43 | 44 | ## 使用源文件 45 | 现在让我们重新开始编程。当你学习一种新的编程语言的时候,你编写运行的第一个程序通常都是“Hello World”程序,这已经成为一种传统了。在你运行“Hello World”程序的时候,它所做的事只是说声:“Hello World”。正如提出“Hello World”程序的Simon Cozens[1]所说: 46 | 47 | > 它是编程之神的传统咒语,可以帮助你更好的学习语言。” 48 | 49 | 启动你选择的编辑器,输入下面这段程序,然后把它保存为helloworld.py。 50 | 51 | **例3.2 使用源文件** 52 | 53 | ```python 54 | #!/usr/bin/python 55 | # Filename : helloworld.py 56 | print 'Hello World' 57 | ``` 58 | 59 | (源文件:[code/helloworld.py][ref_hello_world]) 60 | 61 | 为了运行这个程序,请打开shell(Linux终端或者DOS提示符),然后键入命令 `python helloworld.py` 。如果你使用IDLE,请使用菜单Edit->Run Script或者使用键盘快捷方式 `Ctrl-F5` 。输出如下所示。 62 | 63 | ### 输出 64 | 65 | ``` 66 | $ python helloworld.py 67 | Hello World 68 | ``` 69 | 70 | 如果你得到的输出与上面所示的一样,那么恭喜!——你已经成功地运行了你的第一个Python程序。 71 | 72 | 万一你得到一个错误,那么请确保你键入的程序 准确无误 ,然后再运行一下程序。注意Python是大小写敏感的,即 `print` 与 `Print` 不一样——注意前一个是小写p而后一个是大写P。另外,确保在每一行的开始字符前没有空格或者制表符——我们将在后面讨论为什么这点是重要的。 73 | 74 | ### 它如何工作 75 | 让我们思考一下这个程序的前两行。它们被称作 *注释* ——任何在#符号右面的内容都是注释。注释主要作为提供给程序读者的笔记。 76 | 77 | Python至少应当有第一行那样的特殊形式的注释。它被称作 组织行 ——源文件的头两个字符是#!,后面跟着一个程序。这行告诉你的Linux/Unix系统当你 执行 你的程序的时候,它应该运行哪个解释器。这会在下一节做详细解释。注意,你总是可以通过直接在命令行指定解释器,从而在任何平台上运行你的程序。就如同命令 `python helloworld.py` 一样。 78 | 79 | > **重要** 80 | 81 | > 在你的程序中合理地使用注释以解释一些重要的细节——这将有助于你的程序的读者轻松地理解程序在干什么。记住,这个读者可能就是6个月以后的你! 82 | 83 | 跟在注释之后的是一句Python 语句 ——它只是打印文本“Hello World”。print实际上是一个操作符,而“Hello World”被称为一个字符串——别担心我们会在后面详细解释这些术语。 84 | 85 | ## 可执行的Python程序 86 | 这部分内容只对Linux/Unix用户适用,不过Windows用户可能也对程序的第一行比较好奇。首先我们需要通过 `chmod` 命令,给程序可执行的许可,然后 *运行* 程序。 87 | 88 | ``` 89 | $ chmod a+x helloworld.py 90 | $ ./helloworld.py 91 | Hello World 92 | ``` 93 | 94 | chmod命令用来 *改变* 文件的 *模式* ,给系统中所有用户这个源文件的执行许可。然后我们可以直接通过指定源文件的位置来执行程序。我们使用./来指示程序位于当前目录。 95 | 96 | 为了更加有趣一些,你可以把你的文件名改成仅仅helloworld,然后运行.**/helloworld**。这样,这个程序仍然可以工作,因为系统知道它必须用源文件第一行指定的那个解释器来运行程序。 97 | 98 | 只要知道程序的确切位置,你现在就可以运行程序了——但是如果你希望你的程序能够从各个位置运行呢?那样的话,你可以把你的程序保存在PATH环境变量中的目录之一。每当你运行任何程序,系统会查找列在PATH环境变量中的各个目录。然后运行那个程序。你只要简单地把这个源文件复制到PATH所列目录之一就可以使你的程序在任何位置都可用了。 99 | 100 | ``` 101 | $ echo $PATH 102 | /opt/mono/bin/:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/swaroop/bin 103 | $ cp helloworld.py /home/swaroop/bin/helloworld 104 | $ helloworld 105 | Hello World 106 | ``` 107 | 108 | 我们能够用 **echo** 命令来显示PATH变量,用$给变量名加前缀以向shell表示我们需要这个变量的值。我们看到/home/swaroop/bin是PATH变量中的目录之一。 **swaroop** 是我的系统中使用的用户名。通常,在你的系统中也会有一个相似的目录。你也可以把你选择的目录添加到PATH变量中去——这可以通过运行 **PATH=$PATH:/home/swaroop/mydir** 完成,其中“/home/swaroop/mydir”是我想要添加到PATH变量中的目录。 109 | 110 | 当你想要在任何时间、任何地方运行你的程序的时候,这个方法十分有用。它就好像创造你自己的指令,如同 **cd** 或其他Linux终端或DOS提示符命令那样。 111 | 112 | > **提示** 113 | 114 | > 对于Python来说,程序、脚本或者软件都是指同一个东西。 115 | 116 | ## 获取帮助 117 | 如果你需要某个Python函数或语句的快速信息帮助,那么你可以使用内建的help功能。尤其在你使用带提示符的命令行的时候,它十分有用。比如,运行 `help(str)` ——这会显示str类的帮助。str类用于保存你的程序使用的各种文本(字符串)。类将在后面面向对象编程的章节详细解释。 118 | 119 | > **注释** 120 | 121 | > 按q退出帮助。 122 | 123 | 类似地,你可以获取Python中几乎所有东西的信息。使用help()去学习更多关于help本身的东西! 124 | 125 | 如果你想要获取关于如print那样操作符的帮助,那么你需要正确的设置PYTHONDOCS环境变量。这可以在Linux/Unix中轻松地通过 **env** 命令完成。 126 | 127 | ```python 128 | $ env PYTHONDOCS=/usr/share/doc/python-docs-2.3.4/html/ python 129 | Python 2.3.4 (#1, Oct 26 2004, 16:42:40) 130 | [GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2 131 | Type "help", "copyright", "credits" or "license" for more information. 132 | >>> help('print') 133 | ``` 134 | 135 | 你应该注意到我特意在 `print` 上使用了引号,那样Python就可以理解我是希望获取关于 `print` 的帮助而不是想要它打印东西。 136 | 137 | 注意,我使用的位置是在Fedora Core 3 Linux中的位置——它可能在不同的发行版和版本中有所不同。 138 | 139 | ## 概括 140 | 你现在应该可以方便地编写、保存和运行Python程序了。既然你是一个Python用户,让我们学习更多Python的概念。 141 | 142 | 143 | --- 144 | [1]一位最主要的Perl6/Parrot高手,轰动的《开始Perl》一书的作者。 145 | 146 | 147 | 148 | [ref_edit_list]: http://wiki.python.org/moin/PythonEditors 149 | [ref_IDE_list]: http://wiki.python.org/moin/IntegratedDevelopmentEnvironments 150 | [ref_hello_world]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/helloworld.py -------------------------------------------------------------------------------- /book/第4章 基本概念.md: -------------------------------------------------------------------------------- 1 | 仅仅打印 `Hello World` 就足够了吗?你应该想要做更多的事——你想要得到一些输入,然后做操作,再从中得到一些输出。在Python中,我们可以使用常量和变量来完成这些工作。 2 | 3 | ## 字面意义上的常量 4 | 一个字面意义上的常量的例子是如同5、1.23、9.25e-3这样的数,或者如同'This is a string'、"It's a string!"这样的字符串。它们被称作字面意义上的,因为它们具备 字面 的意义——你按照它们的字面意义使用它们的值。数2总是代表它自己,而不会是别的什么东西——它是一个常量,因为不能改变它的值。因此,所有这些都被称为字面意义上的常量。 5 | 6 | ## 数 7 | 在Python中有4种类型的数——整数、长整数、浮点数和复数。 8 | 9 | - 2是一个整数的例子。 10 | - 长整数不过是大一些的整数。 11 | - 3.23和52.3E-4是浮点数的例子。E标记表示10的幂。在这里,52.3E-4表示52.3 * 10-4。 12 | - (-5+4j)和(2.3-4.6j)是复数的例子。 13 | 14 | ## 字符串 15 | 字符串是 **字符的序列** 。字符串基本上就是一组单词。 16 | 17 | 我几乎可以保证你在每个Python程序中都要用到字符串,所以请特别留心下面这部分的内容。下面告诉你如何在Python中使用字符串。 18 | 19 | - **使用单引号(')** 20 | 21 | 你可以用单引号指示字符串,就如同'Quote me on this'这样。所有的空白,即空格和制表符都照原样保留。 22 | - **使用双引号(")** 23 | 24 | 在双引号中的字符串与单引号中的字符串的使用完全相同,例如"What's your name?"。 25 | - **使用三引号('''或""")** 26 | 利用三引号,你可以指示一个多行的字符串。你可以在三引号中自由的使用单引号和双引号。例如: 27 | 28 | ```python 29 | '''This is a multi-line string. This is the first line. 30 | This is the second line. 31 | "What's your name?," I asked. 32 | He said "Bond, James Bond." 33 | ''' 34 | ``` 35 | - **转义符** 36 | 假设你想要在一个字符串中包含一个单引号('),那么你该怎么指示这个字符串?例如,这个字符串是What's your name?。你肯定不会用'What's your name?'来指示它,因为Python会弄不明白这个字符串从何处开始,何处结束。所以,你需要指明单引号而不是字符串的结尾。可以通过 *转义符* 来完成这个任务。你用\'来指示单引号——注意这个反斜杠。现在你可以把字符串表示为'What\'s your name?'。 37 | 38 | 另一个表示这个特别的字符串的方法是"What's your name?",即用双引号。类似地,要在双引号字符串中使用双引号本身的时候,也可以借助于转义符。另外,你可以用转义符\\\来指示反斜杠本身。 39 | 40 | 值得注意的一件事是,在一个字符串中,行末的单独一个反斜杠表示字符串在下一行继续,而不是开始一个新的行。例如: 41 | 42 | ``` 43 | "This is the first sentence.\ 44 | This is the second sentence." 45 | ``` 46 | 等价于"This is the first sentence. This is the second sentence." 47 | - **自然字符串** 48 | 如果你想要指示某些不需要如转义符那样的特别处理的字符串,那么你需要指定一个自然字符串。自然字符串通过给字符串加上前缀r或R来指定。例如r"Newlines are indicated by \n"。 49 | - **Unicode字符串** 50 | Unicode是书写国际文本的标准方法。如果你想要用你的母语如北印度语或阿拉伯语写文本,那么你需要有一个支持Unicode的编辑器。类似地,Python允许你处理Unicode文本——你只需要在字符串前加上前缀u或U。例如,u"This is a Unicode string."。 51 | 52 | 记住,在你处理文本文件的时候使用Unicode字符串,特别是当你知道这个文件含有用非英语的语言写的文本。 53 | - **字符串是不可变的** 54 | 这意味着一旦你创造了一个字符串,你就不能再改变它了。虽然这看起来像是一件坏事,但实际上它不是。我们将会在后面的程序中看到为什么我们说它不是一个缺点。 55 | - **按字面意义级连字符串** 56 | 如果你把两个字符串按字面意义相邻放着,他们会被Python自动级连。例如,'What\'s' 'your name?'会被自动转为"What's your name?"。 57 | 58 | > **给C/C++程序员的注释** 59 | 60 | > 在Python中没有专门的char数据类型。确实没有需要有这个类型,我相信你不会为此而烦恼。 61 | 62 | > **给Perl/PHP程序员的注释** 63 | 64 | >记住,单引号和双引号字符串是完全相同的——它们没有在任何方面有不同。 65 | 66 | > **给正则表达式用户的注释** 67 | 68 | > 一定要用自然字符串处理正则表达式。否则会需要使用很多的反斜杠。例如,后向引用符可以写成'\\\1'或r'\1'。 69 | 70 | ## 变量 71 | 仅仅使用字面意义上的常量很快就会引发烦恼——我们需要一种既可以储存信息 又可以对它们进行操作的方法。这是为什么要引入 *变量* 。变量就是我们想要的东西——它们的值可以变化,即你可以使用变量存储任何东西。变量只是你的计算机中存储信息的一部分内存。与字面意义上的常量不同,你需要一些能够访问这些变量的方法,因此你给变量名字。 72 | 73 | ## 标识符的命名 74 | 变量是标识符的例子。 *标识符* 是用来标识 *某样东西* 的名字。在命名标识符的时候,你要遵循这些规则: 75 | 76 | - 标识符的第一个字符必须是字母表中的字母(大写或小写)或者一个下划线(‘ _ ’)。 77 | 78 | - 标识符名称的其他部分可以由字母(大写或小写)、下划线(‘ _ ’)或数字(0-9)组成。 79 | 80 | - 标识符名称是对大小写敏感的。例如,myname和myName **不是** 一个标识符。注意前者中的小写n和后者中的大写N。 81 | 82 | - 有效 标识符名称的例子有i、__my_name、name_23和a1b2_c3。 83 | 84 | - 无效 标识符名称的例子有2things、this is spaced out和my-name。 85 | 86 | ## 数据类型 87 | 变量可以处理不同类型的值,称为 **数据类型** 。基本的类型是数和字符串,我们已经讨论过它们了。在后面的章节里面,我们会研究怎么用类创造我们自己的类型。 88 | 89 | ## 对象 90 | 记住,Python把在程序中用到的任何东西都称为 对象 。这是从广义上说的。因此我们不会说“某某 东西 ”,我们说“某个 对象 ”。 91 | 92 | > **给面向对象编程用户的注释** 93 | 94 | > 就每一个东西包括数、字符串甚至函数都是对象这一点来说,Python是极其完全地面向对象的。 95 | 96 | 我们将看一下如何使用变量和字面意义上的常量。保存下面这个例子,然后运行程序。 97 | 98 | > **如何编写Python程序** 99 | 100 | >下面是保存和运行Python程序的标准流程。 101 | 1. 打开你最喜欢的编辑器。 102 | 2. 输入例子中的程序代码。 103 | 3. 用注释中给出的文件名把它保存为一个文件。我按照惯例把所有的Python程序都以扩展名.py保存。 104 | 4. 运行解释器命令 **python program.py** 或者使用IDLE运行程序。你也可以使用先前介绍的可执行的方法。 105 | 106 | **例4.1 使用变量和字面意义上的常量** 107 | 108 | ```python 109 | # Filename : var.py 110 | i = 5 111 | print i 112 | i = i + 1 113 | print i 114 | 115 | s = '''This is a multi-line string. 116 | This is the second line.''' 117 | print s 118 | ``` 119 | 120 | (源文件:[code/var.py][ref_code]) 121 | 122 | ### 输出 123 | 124 | 125 | ``` 126 | $ python var.py 127 | 5 128 | 6 129 | This is a multi-line string. 130 | This is the second line. 131 | ``` 132 | 133 | ### 它如何工作 134 | 下面来说明一下这个程序如何工作。首先我们使用赋值运算符(=)把一个字面意义上的常数5赋给变量i。这一行称为一个语句。语句声明需要做某件事情,在这个地方我们把变量名i与值5连接在一起。接下来,我们用print语句打印i的值,就是把变量的值打印在屏幕上。 135 | 136 | 然后我们对i中存储的值加1,再把它存回i。我们打印它时,得到期望的值6。 137 | 138 | 类似地,我们把一个字面意义上的字符串赋给变量s然后打印它。 139 | 140 | > **给C/C++程序员的注释** 141 | 142 | > 使用变量时只需要给它们赋一个值。不需要声明或定义数据类型。 143 | 144 | ## 逻辑行与物理行 145 | 146 | 物理行是你在编写程序时所 看见 的。逻辑行是Python 看见 的单个语句。Python假定每个 物理行 对应一个 逻辑行 。 147 | 148 | 逻辑行的例子如 `print 'Hello World'` 这样的语句——如果它本身就是一行(就像你在编辑器中看到的那样),那么它也是一个物理行。 149 | 150 | 默认地,Python希望每行都只使用一个语句,这样使得代码更加易读。 151 | 152 | 如果你想要在一个物理行中使用多于一个逻辑行,那么你需要使用分号(;)来特别地标明这种用法。分号表示一个逻辑行/语句的结束。例如: 153 | 154 | 155 | ```python 156 | i = 5 157 | print i 158 | ``` 159 | 160 | 与下面这个相同: 161 | 162 | ```python 163 | i = 5; 164 | print i; 165 | ``` 166 | 167 | 同样也可以写成: 168 | 169 | ```python 170 | i = 5; print i; 171 | ``` 172 | 173 | 甚至可以写成: 174 | 175 | ```python 176 | i = 5; print i 177 | ``` 178 | 179 | 然而,我 **强烈建议** 你坚持 **在每个物理行只写一句逻辑行** 。仅仅当逻辑行太长的时候,在多于一个物理行写一个逻辑行。这些都是为了尽可能避免使用分号,从而让代码更加易读。事实上,我 从来没有 在Python程序中使用过或看到过分号。 180 | 181 | 下面是一个在多个物理行中写一个逻辑行的例子。它被称为 **明确的行连接** 。 182 | 183 | ```python 184 | s = 'This is a string. \ 185 | This continues the string.' 186 | print s 187 | ``` 188 | 189 | 它的输出: 190 | 191 | ``` 192 | This is a string. This continues the string. 193 | ``` 194 | 195 | 类似地, 196 | 197 | ```python 198 | print \ 199 | i 200 | ``` 201 | 202 | 与如下写法效果相同: 203 | 204 | ```python 205 | print i 206 | ``` 207 | 208 | 有时候,有一种暗示的假设,可以使你不需要使用反斜杠。这种情况出现在逻辑行中使用了圆括号、方括号或波形括号的时候。这被称为 **暗示的行连接** 。你会在后面介绍如何使用列表的章节中看到这种用法 209 | 210 | ## 缩进 211 | 空白在Python中是重要的。事实上 **行首的空白是重要的** 。它称为 **缩进** 。在逻辑行首的空白(空格和制表符)用来决定逻辑行的缩进层次,从而用来决定语句的分组。 212 | 213 | 这意味着同一层次的语句 **必须** 有相同的缩进。每一组这样的语句称为一个 **块** 。我们将在后面的章节中看到有关块的用处的例子。 214 | 215 | 你需要记住的一样东西是错误的缩进会引发错误。例如: 216 | 217 | ```python 218 | i = 5 219 | print 'Value is', i # Error! Notice a single space at the start of the line 220 | print 'I repeat, the value is', i 221 | ``` 222 | 223 | 当你运行这个程序的时候,你会得到下面的错误: 224 | 225 | 226 | ``` 227 | File "whitespace.py", line 4 228 | print 'Value is', i # Error! Notice a single space at the start of the line 229 | ^ 230 | SyntaxError: invalid syntax 231 | ``` 232 | 233 | 注意,在第二行的行首有一个空格。Python指示的这个错误告诉我们程序的语法是无效的,即程序没有正确地编写。它告诉你, 你不能随意地开始新的语句块 (当然除了你一直在使用的主块)。何时你能够使用新块,将会在后面的章节,如控制流中详细介绍。 234 | 235 | > **如何缩进** 236 | 237 | > 不要混合使用制表符和空格来缩进,因为这在跨越不同的平台的时候,无法正常工作。我 强烈建议 你在每个缩进层次使用 单个制表符 或 两个或四个空格 。 238 | 选择这三种缩进风格之一。更加重要的是,选择一种风格,然后 **一贯地** 使用它,即 只 使用这一种风格。 239 | 240 | ## 概括 241 | 现在我们已经学习了很多详细的内容,我们可以开始学习更加令你感兴趣的东西,比如控制流语句。在继续学习之前,请确信你对本章的内容清楚明了。 242 | 243 | [ref_code]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/var.py -------------------------------------------------------------------------------- /book/第8章 模块.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 你已经学习了如何在你的程序中定义一次函数而重用代码。如果你想要在其他程序中重用很多函数,那么你该如何编写程序呢?你可能已经猜到了,答案是使用模块。模块基本上就是一个包含了所有你定义的函数和变量的文件。为了在其他程序中重用模块,模块的文件名 **必须** 以.py为扩展名。 3 | 4 | 模块可以从其他程序 输入 以便利用它的功能。这也是我们使用Python标准库的方法。首先,我们将学习如何使用标准库模块。 5 | 6 | ### 使用sys模块 7 | **例8.1 使用sys模块** 8 | 9 | ```python 10 | #!/usr/bin/python 11 | # Filename: using_sys.py 12 | 13 | import sys 14 | 15 | print 'The command line arguments are:' 16 | for i in sys.argv: 17 | print i 18 | 19 | print '\n\nThe PYTHONPATH is', sys.path, '\n' 20 | ``` 21 | 22 | (源文件:[code/using_sys.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_sys.py)) 23 | 24 | ### 输出 25 | 26 | ``` 27 | $ python using_sys.py we are arguments 28 | The command line arguments are: 29 | using_sys.py 30 | we 31 | are 32 | arguments 33 | 34 | 35 | The PYTHONPATH is ['/home/swaroop/byte/code', '/usr/lib/python23.zip', 36 | '/usr/lib/python2.3', '/usr/lib/python2.3/plat-linux2', 37 | '/usr/lib/python2.3/lib-tk', '/usr/lib/python2.3/lib-dynload', 38 | '/usr/lib/python2.3/site-packages', '/usr/lib/python2.3/site-packages/gtk-2.0'] 39 | ``` 40 | 41 | ### 它如何工作 42 | 首先,我们利用import语句 输入 sys模块。基本上,这句语句告诉Python,我们想要使用这个模块。sys模块包含了与Python解释器和它的环境有关的函数。 43 | 44 | 当Python执行import sys语句的时候,它在sys.path变量中所列目录中寻找sys.py模块。如果找到了这个文件,这个模块的主块中的语句将被运行,然后这个模块将能够被你 使用 。注意,初始化过程仅在我们 第一次 输入模块的时候进行。另外,“sys”是“system”的缩写。 45 | 46 | sys模块中的argv变量通过使用点号指明——sys.argv——这种方法的一个优势是这个名称不会与任何在你的程序中使用的argv变量冲突。另外,它也清晰地表明了这个名称是sys模块的一部分。 47 | 48 | sys.argv变量是一个字符串的 列表 (列表会在后面的章节详细解释)。特别地,sys.argv包含了 命令行参数 的列表,即使用命令行传递给你的程序的参数。 49 | 50 | 如果你使用IDE编写运行这些程序,请在菜单里寻找一个指定程序的命令行参数的方法。 51 | 52 | 这里,当我们执行python using\_sys.py we are arguments的时候,我们使用python命令运行using_sys.py模块,后面跟着的内容被作为参数传递给程序。Python为我们把它存储在sys.argv变量中。 53 | 54 | 记住,脚本的名称总是sys.argv列表的第一个参数。所以,在这里,'using_sys.py'是sys.argv[0]、'we'是sys.argv[1]、'are'是sys.argv[2]以及'arguments'是sys.argv[3]。注意,Python从0开始计数,而非从1开始。 55 | 56 | sys.path包含输入模块的目录名列表。我们可以观察到sys.path的第一个字符串是空的——这个空的字符串表示当前目录也是sys.path的一部分,这与PYTHONPATH环境变量是相同的。这意味着你可以直接输入位于当前目录的模块。否则,你得把你的模块放在sys.path所列的目录之一。 57 | 58 | ## 字节编译的.pyc文件 59 | 输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。一种方法是创建 字节编译的文件 ,这些文件以.pyc作为扩展名。字节编译的文件与Python变换程序的中间状态有关(是否还记得Python如何工作的介绍?)。当你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。另外,这些字节编译的文件也是与平台无关的。所以,现在你知道了那些.pyc文件事实上是什么了。 60 | 61 | ## from..import语句 62 | 如果你想要直接输入argv变量到你的程序中(避免在每次使用它时打sys.),那么你可以使用from sys import argv语句。如果你想要输入所有sys模块使用的名字,那么你可以使用from sys import *语句。这对于所有模块都适用。一般说来,应该避免使用from..import而使用import语句,因为这样可以使你的程序更加易读,也可以避免名称的冲突。 63 | 64 | ## 模块的\__name__ 65 | 每个模块都有一个名称,在模块中可以通过语句来找出模块的名称。这在一个场合特别有用——就如前面所提到的,当一个模块被第一次输入的时候,这个模块的主块将被运行。假如我们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,我们该怎么做呢?这可以通过模块的__name__属性完成。 66 | 67 | ### 使用模块的\__name__ 68 | 69 | **例8.2 使用模块的__name__** 70 | 71 | ```python 72 | #!/usr/bin/python 73 | # Filename: using_name.py 74 | 75 | if __name__ == '__main__': 76 | print 'This program is being run by itself' 77 | else: 78 | print 'I am being imported from another module' 79 | ``` 80 | 81 | (源文件:[code/using_name.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_name.py)) 82 | 83 | ### 输出 84 | 85 | ``` 86 | $ python using_name.py 87 | This program is being run by itself 88 | 89 | $ python 90 | >>> import using_name 91 | I am being imported from another module 92 | >>> 93 | ``` 94 | 95 | ### 它如何工作 96 | 每个Python模块都有它的\_\_name\__,如果它是'\_\_main__',这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。 97 | 98 | 99 | ## 制造你自己的模块 100 | 创建你自己的模块是十分简单的,你一直在这样做!每个Python程序也是一个模块。你已经确保它具有.py扩展名了。下面这个例子将会使它更加清晰。 101 | 102 | ### 创建你自己的模块 103 | **例8.3 如何创建你自己的模块** 104 | 105 | ```python 106 | #!/usr/bin/python 107 | # Filename: mymodule.py 108 | 109 | def sayhi(): 110 | print 'Hi, this is mymodule speaking.' 111 | 112 | version = '0.1' 113 | 114 | # End of mymodule.py 115 | ``` 116 | 117 | (源文件:[code/mymodule.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/mymodule.py)) 118 | 119 | 上面是一个 模块 的例子。你已经看到,它与我们普通的Python程序相比并没有什么特别之处。我们接下来将看看如何在我们别的Python程序中使用这个模块。 120 | 121 | 记住这个模块应该被放置在我们输入它的程序的同一个目录中,或者在sys.path所列目录之一。 122 | 123 | 124 | ```python 125 | #!/usr/bin/python 126 | # Filename: mymodule_demo.py 127 | 128 | import mymodule 129 | 130 | mymodule.sayhi() 131 | print 'Version', mymodule.version 132 | ``` 133 | 134 | (源文件:[code/mymodule_demo.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/mymodule_demo.py)) 135 | 136 | ### 输出 137 | 138 | ``` 139 | $ python mymodule_demo.py 140 | Hi, this is mymodule speaking. 141 | Version 0.1 142 | ``` 143 | 144 | ### 它如何工作 145 | 146 | 注意我们使用了相同的点号来使用模块的成员。Python很好地重用了相同的记号来,使我们这些Python程序员不需要不断地学习新的方法。 147 | 148 | ### from..import 149 | 下面是一个使用from..import语法的版本。 150 | 151 | ```python 152 | #!/usr/bin/python 153 | # Filename: mymodule_demo2.py 154 | 155 | from mymodule import sayhi, version 156 | # Alternative: 157 | # from mymodule import * 158 | 159 | sayhi() 160 | print 'Version', version 161 | ``` 162 | 163 | (源文件:[code/mymodule_demo2.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/mymodule_demo2.py)) 164 | 165 | mymodule\_demo2.py的输出与mymodule_demo.py完全相同。 166 | 167 | ## dir()函数 168 | 你可以使用内建的dir函数来列出模块定义的标识符。标识符有函数、类和变量。 169 | 170 | 当你为dir()提供一个模块名的时候,它返回模块定义的名称列表。如果不提供参数,它返回当前模块中定义的名称列表。 171 | 172 | ### 使用dir函数 173 | **例8.4 使用dir函数** 174 | 175 | ``` 176 | $ python 177 | >>> import sys 178 | >>> dir(sys) # get list of attributes for sys module 179 | ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', 180 | '__stdin__', '__stdout__', '_getframe', 'api_version', 'argv', 181 | 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 182 | 'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 183 | 'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval', 184 | 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 185 | 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode', 186 | 'meta_path','modules', 'path', 'path_hooks', 'path_importer_cache', 187 | 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 188 | 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 189 | 'version', 'version_info', 'warnoptions'] 190 | >>> dir() # get list of attributes for current module 191 | ['__builtins__', '__doc__', '__name__', 'sys'] 192 | >>> 193 | >>> a = 5 # create a new variable 'a' 194 | >>> dir() 195 | ['__builtins__', '__doc__', '__name__', 'a', 'sys'] 196 | >>> 197 | >>> del a # delete/remove a name 198 | >>> 199 | >>> dir() 200 | ['__builtins__', '__doc__', '__name__', 'sys'] 201 | >>> 202 | ``` 203 | 204 | ### 它如何工作 205 | 首先,我们来看一下在输入的sys模块上使用dir。我们看到它包含一个庞大的属性列表。 206 | 207 | 接下来,我们不给dir函数传递参数而使用它——默认地,它返回当前模块的属性列表。注意,输入的模块同样是列表的一部分。 208 | 209 | 为了观察dir的作用,我们定义一个新的变量a并且给它赋一个值,然后检验dir,我们观察到在列表中增加了以上相同的值。我们使用del语句删除当前模块中的变量/属性,这个变化再一次反映在dir的输出中。 210 | 211 | 关于del的一点注释——这个语句在运行后被用来 删除 一个变量/名称。在这个例子中,del a,你将无法再使用变量a——它就好像从来没有存在过一样。 212 | 213 | ## 概括 214 | 模块的用处在于它能为你在别的程序中重用它提供的服务和功能。Python附带的标准库就是这样一组模块的例子。我们已经学习了如何使用这些模块以及如何创造我们自己的模块。 215 | 216 | 接下来,我们将学习一些有趣的概念,它们称为数据结构。 217 | -------------------------------------------------------------------------------- /book/第6章 控制流.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 在到目前为止我们所见到的程序中,总是有一系列的语句,Python忠实地按照它们的顺序执行它们。如果你想要改变语句流的执行顺序,该怎么办呢?例如,你想要让程序做一些决定,根据不同的情况做不同的事情,例如根据时间打印“早上好”或者“晚上好”。 3 | 4 | 你可能已经猜到了,这是通过控制流语句实现的。在Python中有三种控制流语句——if、for和while。 5 | 6 | ## if语句 7 | if语句用来检验一个条件, 如果条件为真,我们运行一块语句(称为 if-块 ), 否则 我们处理另外一块语句(称为 else-块 )。 else 从句是可选的。 8 | 9 | ### 使用if语句 10 | **例6.1 使用if语句** 11 | 12 | ```python 13 | #!/usr/bin/python 14 | # Filename: if.py 15 | 16 | number = 23 17 | guess = int(raw_input('Enter an integer : ')) 18 | 19 | if guess == number: 20 | print 'Congratulations, you guessed it.' # New block starts here 21 | print "(but you do not win any prizes!)" # New block ends here 22 | elif guess < number: 23 | print 'No, it is a little higher than that' # Another block 24 | # You can do whatever you want in a block ... 25 | else: 26 | print 'No, it is a little lower than that' 27 | # you must have guess > number to reach here 28 | 29 | print 'Done' 30 | # This last statement is always executed, after the if statement is executed 31 | ``` 32 | 33 | (源文件:[code/if.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/if.py)) 34 | 35 | ### 输出 36 | 37 | ``` 38 | $ python if.py 39 | Enter an integer : 50 40 | No, it is a little lower than that 41 | Done 42 | $ python if.py 43 | Enter an integer : 22 44 | No, it is a little higher than that 45 | Done 46 | $ python if.py 47 | Enter an integer : 23 48 | Congratulations, you guessed it. 49 | (but you do not win any prizes!) 50 | Done 51 | ``` 52 | 53 | ### 它如何工作 54 | 在这个程序中,我们从用户处得到猜测的数,然后检验这个数是否是我们手中的那个。我们把变量number设置为我们想要的任何整数,在这个例子中是23。然后,我们使用raw_input()函数取得用户猜测的数字。函数只是重用的程序段。我们将在下一章学习更多关于函数的知识。 55 | 56 | 我们为内建的 `raw_input` 函数提供一个字符串,这个字符串被打印在屏幕上,然后等待用户的输入。一旦我们输入一些东西,然后按 **回车** 键之后,函数返回输入。对于raw_input函数来说是一个字符串。我们通过int把这个字符串转换为整数,并把它存储在变量guess中。事实上,int是一个类,不过你想在对它所需了解的只是它把一个字符串转换为一个整数(假设这个字符串含有一个有效的整数文本信息)。 57 | 58 | 接下来,我们将用户的猜测与我们选择的数做比较。如果他们相等,我们打印一个成功的消息。注意我们使用了缩进层次来告诉Python每个语句分别属于哪一个块。这就是为什么缩进在Python如此重要的原因。我希望你能够坚持“每个缩进层一个制表符”的规则。你是这样的吗? 59 | 60 | 注意if语句在结尾处包含一个冒号——我们通过它告诉Python下面跟着一个语句块。 61 | 62 | 然后,我们检验猜测是否小于我们的数,如果是这样的,我们告诉用户它的猜测大了一点。我们在这里使用的是elif从句,它事实上把两个相关联的if else-if else语句合并为一个if-elif-else语句。这使得程序更加简单,并且减少了所需的缩进数量。 63 | 64 | elif和else从句都必须在逻辑行结尾处有一个冒号,下面跟着一个相应的语句块(当然还包括正确的缩进)。 65 | 66 | 你也可以在一个if块中使用另外一个if语句,等等——这被称为嵌套的if语句。 67 | 68 | 记住,elif和else部分是可选的。一个最简单的有效if语句是: 69 | 70 | ```python 71 | if True: 72 | print 'Yes, it is true' 73 | ``` 74 | 75 | 在Python执行完一个完整的if语句以及与它相关联的elif和else从句之后,它移向if语句块的下一个语句。在这个例子中,这个语句块是主块。程序从主块开始执行,而下一个语句是print 'Done'语句。在这之后,Python看到程序的结尾,简单的结束运行。 76 | 77 | 尽管这是一个非常简单的程序,但是我已经在这个简单的程序中指出了许多你应该注意的地方。所有这些都是十分直接了当的(对于那些拥有C/C++背景的用户来说是尤为简单的)。它们在开始时会引起你的注意,但是以后你会对它们感到熟悉、“自然”。 78 | 79 | 80 | > **给C/C++程序员的注释** 81 | 82 | > 在Python中没有switch语句。你可以使用if..elif..else语句来完成同样的工作(在某些场合,使用字典会更加快捷。) 83 | 84 | ## while语句 85 | 只要在一个条件为真的情况下,while语句允许你重复执行一块语句。while语句是所谓 循环 语句的一个例子。while语句有一个可选的else从句。 86 | 87 | ### 使用while语句 88 | **例6.2 使用while语句** 89 | 90 | ```python 91 | #!/usr/bin/python 92 | # Filename: while.py 93 | 94 | number = 23 95 | running = True 96 | 97 | while running: 98 | guess = int(raw_input('Enter an integer : ')) 99 | 100 | if guess == number: 101 | print 'Congratulations, you guessed it.' 102 | running = False # this causes the while loop to stop 103 | elif guess < number: 104 | print 'No, it is a little higher than that' 105 | else: 106 | print 'No, it is a little lower than that' 107 | else: 108 | print 'The while loop is over.' 109 | # Do anything else you want to do here 110 | 111 | print 'Done' 112 | ``` 113 | 114 | (源文件:[code/while.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/while.py)) 115 | 116 | ### 输出 117 | 118 | 119 | ``` 120 | $ python while.py 121 | Enter an integer : 50 122 | No, it is a little lower than that. 123 | Enter an integer : 22 124 | No, it is a little higher than that. 125 | Enter an integer : 23 126 | Congratulations, you guessed it. 127 | The while loop is over. 128 | Done 129 | ``` 130 | 131 | ### 它如何工作 132 | 在这个程序中,我们仍然使用了猜数游戏作为例子,但是这个例子的优势在于用户可以不断的猜数,直到他猜对为止——这样就不需要像前面那个例子那样为每次猜测重复执行一遍程序。这个例子恰当地说明了while语句的使用。 133 | 134 | 我们把raw_input和if语句移到了while循环内,并且在while循环开始前把running变量设置为True。首先,我们检验变量running是否为True,然后执行后面的 while-块 。在执行了这块程序之后,再次检验条件,在这个例子中,条件是running变量。如果它是真的,我们再次执行while-块,否则,我们继续执行可选的else-块,并接着执行下一个语句。 135 | 136 | 当while循环条件变为False的时候,else块才被执行——这甚至也可能是在条件第一次被检验的时候。如果while循环有一个else从句,它将始终被执行,除非你的while循环将永远循环下去不会结束! 137 | 138 | True和False被称为布尔类型。你可以分别把它们等效地理解为值1和0。在检验重要条件的时候,布尔类型十分重要,它们并不是真实的值1。 139 | 140 | else块事实上是多余的,因为你可以把其中的语句放在同一块(与while相同)中,跟在while语句之后,这样可以取得相同的效果。 141 | 142 | 143 | > **给C/C++程序员的注释** 144 | 145 | > 记住,你可以在while循环中使用一个else从句。 146 | 147 | 148 | ## for循环 149 | for..in是另外一个循环语句,它在一序列的对象上 递归 即逐一使用队列中的每个项目。我们会在后面的章节中更加详细地学习序列。 150 | 151 | ### 使用for语句 152 | **例6.3 使用for语句** 153 | 154 | ```python 155 | #!/usr/bin/python 156 | # Filename: for.py 157 | 158 | for i in range(1, 5): 159 | print i 160 | else: 161 | print 'The for loop is over' 162 | ``` 163 | 164 | ### 输出 165 | 166 | ``` 167 | $ python for.py 168 | 1 169 | 2 170 | 3 171 | 4 172 | The for loop is over 173 | ``` 174 | 175 | ### 它如何工作 176 | 在这个程序中,我们打印了一个 序列 的数。我们使用内建的range函数生成这个数的序列。 177 | 178 | 我们所做的只是提供两个数,range返回一个序列的数。这个序列从第一个数开始到第二个数为止。例如,range(1,5)给出序列[1, 2, 3, 4]。默认地,range的步长为1。如果我们为range提供第三个数,那么它将成为步长。例如,range(1,5,2)给出[1,3]。记住,range 向上 延伸到第二个数,即它 **不** 包含第二个数。 179 | 180 | for循环在这个范围内递归——for i in range(1,5)等价于for i in [1, 2, 3, 4],这就如同把序列中的每个数(或对象)赋值给i,一次一个,然后以每个i的值执行这个程序块。在这个例子中,我们只是打印i的值。 181 | 182 | 记住,else部分是可选的。如果包含else,它总是在for循环结束后执行一次,除非遇到break语句。 183 | 184 | 记住,for..in循环对于任何序列都适用。这里我们使用的是一个由内建range函数生成的数的列表,但是广义说来我们可以使用任何种类的由任何对象组成的序列!我们会在后面的章节中详细探索这个观点。 185 | 186 | 187 | > **给C/C++/Java/C#程序员的注释** 188 | 189 | > Python的for循环从根本上不同于C/C++的for循环。C#程序员会注意到Python的for循环与C#中的foreach循环十分类似。Java程序员会注意到它与Java 1.5中的for (int i : IntArray)相似。 190 | 在C/C++中,如果你想要写for (int i = 0; i < 5; i++),那么用Python,你写成for i in range(0,5)。你会注意到,Python的for循环更加简单、明白、不易出错。 191 | 192 | ## break语句 193 | break语句是用来 终止 循环语句的,即哪怕循环条件没有称为False或序列还没有被完全递归,也停止执行循环语句。 194 | 195 | 一个重要的注释是,如果你从for或while循环中 终止 ,任何对应的循环else块将 **不** 执行。 196 | 197 | ### 使用break语句 198 | **例6.4 使用break语句** 199 | 200 | ```python 201 | #!/usr/bin/python 202 | # Filename: break.py 203 | 204 | while True: 205 | s = raw_input('Enter something : ') 206 | if s == 'quit': 207 | break 208 | print 'Length of the string is', len(s) 209 | print 'Done' 210 | ``` 211 | 212 | (源文件:[code/break.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/break.py)) 213 | 214 | ### 输出 215 | 216 | ``` 217 | $ python break.py 218 | Enter something : Programming is fun 219 | Length of the string is 18 220 | Enter something : When the work is done 221 | Length of the string is 21 222 | Enter something : if you wanna make your work also fun: 223 | Length of the string is 37 224 | Enter something : use Python! 225 | Length of the string is 12 226 | Enter something : quit 227 | Done 228 | ``` 229 | 230 | ### 它如何工作 231 | 在这个程序中,我们反复地取得用户地输入,然后打印每次输入地长度。我们提供了一个特别的条件来停止程序,即检验用户的输入是否是'quit'。通过 终止 循环到达程序结尾来停止程序。 232 | 233 | 输入字符串的长度通过内建的len函数取得。 234 | 235 | 记住,break语句也可以在for循环中使用。 236 | 237 | ### G2的Python诗 238 | 我在这里输入的是我所写的一段小诗,称为 **G2的Python诗** : 239 | 240 | ``` 241 | Programming is fun 242 | When the work is done 243 | if you wanna make your work also fun: 244 | use Python! 245 | ``` 246 | 247 | ## continue语句 248 | continue语句被用来告诉Python跳过当前循环块中的剩余语句,然后 继续 进行下一轮循环。 249 | 250 | ### 使用continue语句 251 | **例6.5 使用continue语句** 252 | 253 | ```python 254 | #!/usr/bin/python 255 | # Filename: continue.py 256 | 257 | while True: 258 | s = raw_input('Enter something : ') 259 | if s == 'quit': 260 | break 261 | if len(s) < 3: 262 | continue 263 | print 'Input is of sufficient length' 264 | # Do other kinds of processing here... 265 | ``` 266 | 267 | (源文件:[code/continue.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/continue.py)) 268 | 269 | ### 输出 270 | 271 | 272 | ``` 273 | $ python continue.py 274 | Enter something : a 275 | Enter something : 12 276 | Enter something : abc 277 | Input is of sufficient length 278 | Enter something : quit 279 | ``` 280 | 281 | ### 它如何工作 282 | 在这个程序中,我们从用户处取得输入,但是我们仅仅当它们有至少3个字符长的时候才处理它们。所以,我们使用内建的len函数来取得长度。如果长度小于3,我们将使用continue语句忽略块中的剩余的语句。否则,这个循环中的剩余语句将被执行,我们可以在这里做我们希望的任何处理。 283 | 284 | 注意,continue语句对于for循环也有效。 285 | 286 | ## 概括 287 | 我们已经学习了如何使用三种控制流语句—— `if` 、 `while` 和 `for` 以及与它们相关的 `break` 和 `continue` 语句。它们是Python中最常用的部分,熟悉这些控制流是应当掌握的基本技能。 288 | 289 | 接下来,我们将学习如何创建和使用函数。 -------------------------------------------------------------------------------- /book/第7章 函数.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 函数是重用的程序段。它们允许你给一块语句一个名称,然后你可以在你的程序的任何地方使用这个名称任意多次地运行这个语句块。这被称为 调用 函数。我们已经使用了许多内建的函数,比如len和range。 3 | 4 | 函数通过def关键字 **定义** 。def关键字后跟一个函数的 标识符 名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。接下来是一块语句,它们是函数体。下面这个例子将说明这事实上是十分简单的: 5 | 6 | ### 定义函数 7 | **例7.1 定义函数** 8 | 9 | ```python 10 | #!/usr/bin/python 11 | # Filename: function1.py 12 | 13 | def sayHello(): 14 | print 'Hello World!' # block belonging to the function 15 | 16 | sayHello() # call the function 17 | ``` 18 | 19 | (源文件:[code/function1.py][ref_fc1]) 20 | 21 | ### 输出 22 | 23 | ``` 24 | $ python function1.py 25 | Hello World! 26 | ``` 27 | 28 | ### 它如何工作 29 | 我们使用上面解释的语法定义了一个称为sayHello的函数。这个函数不使用任何参数,因此在圆括号中没有声明任何变量。参数对于函数而言,只是给函数的输入,以便于我们可以传递不同的值给函数,然后得到相应的结果。 30 | 31 | ## 函数形参 32 | 函数取得的参数是你提供给函数的值,这样函数就可以利用这些值 做 一些事情。这些参数就像变量一样,只不过它们的值是在我们调用函数的时候定义的,而非在函数本身内赋值。 33 | 34 | 参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式提供值。注意我们使用过的术语——函数中的参数名称为 形参 而你提供给函数调用的值称为 实参 。 35 | 36 | ### 使用函数形参 37 | **例7.2 使用函数形参** 38 | 39 | ```python 40 | #!/usr/bin/python 41 | # Filename: func_param.py 42 | 43 | def printMax(a, b): 44 | if a > b: 45 | print a, 'is maximum' 46 | else: 47 | print b, 'is maximum' 48 | 49 | printMax(3, 4) # directly give literal values 50 | 51 | x = 5 52 | y = 7 53 | 54 | printMax(x, y) # give variables as arguments 55 | ``` 56 | 57 | (源文件:[code/func_param.py][ref_fc_pa]) 58 | 59 | ### 输出 60 | 这里,我们定义了一个称为printMax的函数,这个函数需要两个形参,叫做a和b。我们使用if..else语句找出两者之中较大的一个数,并且打印较大的那个数。 61 | 62 | 在第一个printMax使用中,我们直接把数,即实参,提供给函数。在第二个使用中,我们使用变量调用函数。printMax(x, y)使实参x的值赋给形参a,实参y的值赋给形参b。在两次调用中,printMax函数的工作完全相同。 63 | 64 | ## 局部变量 65 | 当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。 66 | 67 | ### 使用局部变量 68 | **例7.3 使用局部变量** 69 | 70 | ```python 71 | #!/usr/bin/python 72 | # Filename: func_local.py 73 | 74 | def func(x): 75 | print 'x is', x 76 | x = 2 77 | print 'Changed local x to', x 78 | 79 | x = 50 80 | func(x) 81 | print 'x is still', x 82 | ``` 83 | 84 | (源文件:[code/func_local.py][ref_fc_lc]) 85 | 86 | ### 输出 87 | 88 | ``` 89 | $ python func_local.py 90 | x is 50 91 | Changed local x to 2 92 | x is still 50 93 | ``` 94 | 95 | ### 它如何工作 96 | 在函数中,我们第一次使用x的 值 的时候,Python使用函数声明的形参的值。 97 | 98 | 接下来,我们把值2赋给x。x是函数的局部变量。所以,当我们在函数内改变x的值的时候,在主块中定义的x不受影响。 99 | 100 | 在最后一个print语句中,我们证明了主块中的x的值确实没有受到影响。 101 | 102 | ### 使用global语句 103 | 如果你想要为一个定义在函数外的变量赋值,那么你就得告诉Python这个变量名不是局部的,而是 全局 的。我们使用global语句完成这一功能。没有global语句,是不可能为定义在函数外的变量赋值的。 104 | 105 | 你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,我并不鼓励你这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义的。使用global语句可以清楚地表明变量是在外面的块定义的。 106 | 107 | **例7.4 使用global语句** 108 | 109 | ```python 110 | #!/usr/bin/python 111 | # Filename: func_global.py 112 | 113 | def func(): 114 | global x 115 | 116 | print 'x is', x 117 | x = 2 118 | print 'Changed local x to', x 119 | 120 | x = 50 121 | func() 122 | print 'Value of x is', x 123 | ``` 124 | 125 | (源文件:[code/func_global.py][ref_fc_gl]) 126 | 127 | ### 输出 128 | 129 | ``` 130 | $ python func_global.py 131 | x is 50 132 | Changed global x to 2 133 | Value of x is 2 134 | ``` 135 | 136 | ### 它如何工作 137 | global语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反映在我们在主块中使用x的值的时候。 138 | 139 | 你可以使用同一个global语句指定多个全局变量。例如global x, y, z。 140 | 141 | ## 默认参数值 142 | 对于一些函数,你可能希望它的一些参数是 可选 的,如果用户不想要为这些参数提供值的话,这些参数就使用默认值。这个功能借助于默认参数值完成。你可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。 143 | 144 | 注意,默认参数值应该是一个参数。更加准确的说,默认参数值应该是不可变的——这会在后面的章节中做详细解释。从现在开始,请记住这一点。 145 | 146 | ### 使用默认参数值 147 | **例7.5 使用默认参数值** 148 | 149 | ```python 150 | #!/usr/bin/python 151 | # Filename: func_default.py 152 | 153 | def say(message, times = 1): 154 | print message * times 155 | 156 | say('Hello') 157 | say('World', 5) 158 | ``` 159 | 160 | (源文件:[code/func_default.py][ref_fc_de]) 161 | 162 | ### 输出 163 | 164 | ``` 165 | $ python func_default.py 166 | Hello 167 | WorldWorldWorldWorldWorld 168 | ``` 169 | 170 | ### 它如何工作 171 | 名为say的函数用来打印一个字符串任意所需的次数。如果我们不提供一个值,那么默认地,字符串将只被打印一遍。我们通过给形参times指定默认参数值1来实现这一功能。 172 | 173 | 在第一次使用say的时候,我们只提供一个字符串,函数只打印一次字符串。在第二次使用say的时候,我们提供了字符串和参数5,表明我们想要 说 这个字符串消息5遍。 174 | 175 | > **重要** 176 | 177 | > 只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。 178 | 这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5)是有效的,但是def func(a=5, b)是 无效 的。 179 | 180 | ## 关键参数 181 | 如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参数赋值——这被称作 关键参数 ——我们使用名字(关键字)而不是位置(我们前面所一直使用的方法)来给函数指定实参。 182 | 183 | 这样做有两个 优势 ——一,由于我们不必担心参数的顺序,使用函数变得更加简单了。二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。 184 | 185 | ### 使用关键参数 186 | **例7.6 使用关键参数** 187 | 188 | ```python 189 | #!/usr/bin/python 190 | # Filename: func_key.py 191 | 192 | def func(a, b=5, c=10): 193 | print 'a is', a, 'and b is', b, 'and c is', c 194 | 195 | func(3, 7) 196 | func(25, c=24) 197 | func(c=50, a=100) 198 | ``` 199 | 200 | (源文件:[code/func_key.py][ref_fc_key]) 201 | 202 | ### 输出 203 | 204 | ``` 205 | $ python func_key.py 206 | a is 3 and b is 7 and c is 10 207 | a is 25 and b is 5 and c is 24 208 | a is 100 and b is 5 and c is 50 209 | ``` 210 | 211 | 名为func的函数有一个没有默认值的参数,和两个有默认值的参数。 212 | 213 | 在第一次使用函数的时候, func(3, 7),参数a得到值3,参数b得到值7,而参数c使用默认值10。 214 | 215 | 在第二次使用函数func(25, c=24)的时候,根据实参的位置变量a得到值25。根据命名,即关键参数,参数c得到值24。变量b根据默认值,为5。 216 | 217 | 在第三次使用func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。 218 | 219 | ## return语句 220 | return语句用来从一个函数 返回 即跳出函数。我们也可选从函数 返回一个值 。 221 | 222 | ### 使用字面意义上的语句 223 | 224 | **例7.7 使用字面意义上的语句** 225 | 226 | 227 | ```python 228 | #!/usr/bin/python 229 | # Filename: func_return.py 230 | 231 | def maximum(x, y): 232 | if x > y: 233 | return x 234 | else: 235 | return y 236 | 237 | print maximum(2, 3) 238 | ``` 239 | 240 | (源文件:[code/func_return.py][ref_fc_re]) 241 | 242 | ### 输出 243 | 244 | ``` 245 | $ python func_return.py 246 | 3 247 | ``` 248 | 249 | ### 它如何工作 250 | maximum函数返回参数中的最大值,在这里是提供给函数的数。它使用简单的if..else语句来找出较大的值,然后 返回 那个值。 251 | 252 | 注意,没有返回值的return语句等价于return None。None是Python中表示没有任何东西的特殊类型。例如,如果一个变量的值为None,可以表示它没有值。 253 | 254 | 除非你提供你自己的return语句,每个函数都在结尾暗含有return None语句。通过运行print someFunction(),你可以明白这一点,函数someFunction没有使用return语句,如同: 255 | 256 | 257 | ```python 258 | def someFunction(): 259 | pass 260 | ``` 261 | 262 | pass语句在Python中表示一个空的语句块。 263 | 264 | ## DocStrings 265 | Python有一个很奇妙的特性,称为 文档字符串 ,它通常被简称为 docstrings 。DocStrings是一个重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序运行的时候,从函数恢复文档字符串! 266 | 267 | ### 使用DocStrings 268 | 269 | **例7.8 使用DocStrings** 270 | 271 | ```python 272 | #!/usr/bin/python 273 | # Filename: func_doc.py 274 | 275 | def printMax(x, y): 276 | '''Prints the maximum of two numbers. 277 | 278 | The two values must be integers.''' 279 | x = int(x) # convert to integers, if possible 280 | y = int(y) 281 | 282 | if x > y: 283 | print x, 'is maximum' 284 | else: 285 | print y, 'is maximum' 286 | 287 | printMax(3, 5) 288 | print printMax.__doc__ 289 | ``` 290 | 291 | (源文件:[code/func_doc.py][ref_fc_doc]) 292 | 293 | ### 输出 294 | 295 | ``` 296 | $ python func_doc.py 297 | 5 is maximum 298 | Prints the maximum of two numbers. 299 | 300 | The two values must be integers. 301 | 302 | ``` 303 | 304 | ### 它如何工作 305 | 在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,DocStrings也适用于模块和类,我们会在后面相应的章节学习它们。 306 | 307 | 文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。 308 | 309 | 你可以使用__doc__(注意双下划线)调用printMax函数的文档字符串属性(属于函数的名称)。请记住Python把 每一样东西 都作为对象,包括这个函数。我们会在后面的类一章学习更多关于对象的知识。 310 | 311 | 如果你已经在Python中使用过help(),那么你已经看到过DocStings的使用了!它所做的只是抓取函数的__doc__属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你的程序中包括help(printMax)。记住按 **q** 退出help。 312 | 313 | 自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任何正式函数编写文档字符串。随你的Python发行版附带的 **pydoc** 命令,与help()类似地使用DocStrings。 314 | 315 | ## 概括 316 | 我们已经学习了函数的很多方面的知识,不过注意还有一些方面我们没有涉及。然而,我们已经覆盖了大多数在日常使用中,你可能用到的Python函数知识。 317 | 318 | 接下来,我们将学习如何创建和使用Python模块。 319 | 320 | 321 | [ref_fc_doc]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_doc.py 322 | [ref_fc_re]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_return.py 323 | [ref_fc_key]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_key.py 324 | [ref_fc_de]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_default.py 325 | [ref_fc_gl]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_global.py 326 | [ref_fc_lc]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_local.py 327 | [ref_fc_pa]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/func_param.py 328 | [ref_fc1]: http://woodpecker.org.cn/abyteofpython_cn/chinese/code/function1.py 329 | -------------------------------------------------------------------------------- /book/第11章 面向对象的编程.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 到目前为止,在我们的程序中,我们都是根据操作数据的函数或语句块来设计程序的。这被称为 面向过程的 编程。还有一种把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。这种方法称为 面向对象的 编程理念。在大多数时候你可以使用过程性编程,但是有些时候当你想要编写大型程序或是寻求一个更加合适的解决方案的时候,你就得使用面向对象的编程技术。 3 | 4 | 类和对象是面向对象编程的两个主要方面。类创建一个新类型,而对象这个类的 实例 。这类似于你有一个int类型的变量,这存储整数的变量是int类的实例(对象)。 5 | 6 | > **给C/C++/Java/C#程序员的注释** 7 | 8 | > 注意,即便是整数也被作为对象(属于int类)。这和C++、Java(1.5版之前)把整数纯粹作为类型是不同的。通过help(int)了解更多这个类的详情。 C#和Java 1.5程序员会熟悉这个概念,因为它类似与 封装与解封装 的概念。 9 | 10 | 对象可以使用普通的 属于 对象的变量存储数据。属于一个对象或类的变量被称为域。对象也可以使用 属于 类的函数来具有功能。这样的函数被称为类的方法。这些术语帮助我们把它们与孤立的函数和变量区分开来。域和方法可以合称为类的属性。 11 | 12 | 域有两种类型——属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。 13 | 14 | 类使用class关键字创建。类的域和方法被列在一个缩进块中。 15 | 16 | ## self 17 | 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。 18 | 19 | 虽然你可以给这个参数任何名称,但是 强烈建议 你使用self这个名称——其他名称都是不赞成你使用的。使用一个标准的名称有很多优点——你的程序读者可以迅速识别它,如果使用self的话,还有些IDE(集成开发环境)也可以帮助你。 20 | 21 | > **给C++/Java/C#程序员的注释** 22 | 23 | > Python中的self等价于C++中的self指针和Java、C#中的this参考。 24 | 25 | 你一定很奇怪Python如何给self赋值以及为何你不需要给它赋值。举一个例子会使此变得清晰。假如你有一个类称为MyClass和这个类的一个实例MyObject。当你调用这个对象的方法MyObject.method(arg1, arg2)的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2)——这就是self的原理了。 26 | 27 | 这也意味着如果你有一个不需要参数的方法,你还是得给这个方法定义一个self参数。 28 | 29 | ## 类 30 | 一个尽可能简单的类如下面这个例子所示。 31 | 32 | ### 创建一个类 33 | **例11.1 创建一个类** 34 | 35 | ```python 36 | #!/usr/bin/python 37 | # Filename: simplestclass.py 38 | 39 | class Person: 40 | pass # An empty block 41 | 42 | p = Person() 43 | print p 44 | ``` 45 | 46 | (源文件:[code/simplestclass.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/simplestclass.py)) 47 | 48 | ### 输出 49 | 50 | ``` 51 | $ python simplestclass.py 52 | <__main__.Person instance at 0xf6fcb18c> 53 | ``` 54 | 55 | ### 它如何工作 56 | 57 | 我们使用class语句后跟类名,创建了一个新的类。这后面跟着一个缩进的语句块形成类体。在这个例子中,我们使用了一个空白块,它由pass语句表示。 58 | 59 | 接下来,我们使用类名后跟一对圆括号来创建一个对象/实例。(我们将在下面的章节中学习更多的如何创建实例的方法)。为了验证,我们简单地打印了这个变量的类型。它告诉我们我们已经在__main__模块中有了一个Person类的实例。 60 | 61 | 可以注意到存储对象的计算机内存地址也打印了出来。这个地址在你的计算机上会是另外一个值,因为Python可以在任何空位存储对象。 62 | 63 | ## 对象的方法 64 | 我们已经讨论了类/对象可以拥有像函数一样的方法,这些方法与函数的区别只是一个额外的self变量。现在我们来学习一个例子。 65 | 66 | ### 使用对象的方法 67 | **例11.2 使用对象的方法** 68 | 69 | ```python 70 | #!/usr/bin/python 71 | # Filename: method.py 72 | 73 | class Person: 74 | def sayHi(self): 75 | print 'Hello, how are you?' 76 | 77 | p = Person() 78 | p.sayHi() 79 | 80 | # This short example can also be written as Person().sayHi() 81 | ``` 82 | 83 | (源文件:[code/method.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/method.py)) 84 | 85 | ### 输出 86 | 87 | ``` 88 | $ python method.py 89 | Hello, how are you? 90 | ``` 91 | 92 | ### 它如何工作 93 | 这里我们看到了self的用法。注意sayHi方法没有任何参数,但仍然在函数定义时有self。 94 | 95 | ## __init__方法 96 | 97 | 在Python的类中有很多方法的名字有特殊的重要意义。现在我们将学习\_\_init\_\_方法的意义。 98 | 99 | \_\_init\_\_方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的 初始化 。注意,这个名称的开始和结尾都是双下划线。 100 | 101 | ### 使用__init__方法 102 | **例11.3 使用\_\_init\_\_方法** 103 | 104 | ```python 105 | #!/usr/bin/python 106 | # Filename: class_init.py 107 | 108 | class Person: 109 | def __init__(self, name): 110 | self.name = name 111 | def sayHi(self): 112 | print 'Hello, my name is', self.name 113 | 114 | p = Person('Swaroop') 115 | p.sayHi() 116 | 117 | # This short example can also be written as Person('Swaroop').sayHi() 118 | ``` 119 | 120 | (源文件:[code/class_init.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/class_init.py)) 121 | 122 | ### 输出 123 | 124 | ``` 125 | $ python class_init.py 126 | Hello, my name is Swaroop 127 | ``` 128 | 129 | ### 它如何工作 130 | 这里,我们把\_\_init\_\_方法定义为取一个参数name(以及普通的参数self)。在这个\_\_init\_\_里,我们只是创建一个新的域,也称为name。注意它们是两个不同的变量,尽管它们有相同的名字。点号使我们能够区分它们。 131 | 132 | 最重要的是,我们没有专门调用\_\_init\_\_方法,只是在创建一个类的新实例的时候,把参数包括在圆括号内跟在类名后面,从而传递给\_\_init\_\_方法。这是这种方法的重要之处。 133 | 134 | 现在,我们能够在我们的方法中使用self.name域。这在sayHi方法中得到了验证。 135 | 136 | > **给C++/Java/C#程序员的注释** 137 | 138 | > __init__方法类似于C++、C#和Java中的 constructor 。 139 | 140 | ## 类与对象的方法 141 | 我们已经讨论了类与对象的功能部分,现在我们来看一下它的数据部分。事实上,它们只是与类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。 142 | 143 | 有两种类型的 域 ——类的变量和对象的变量,它们根据是类还是对象 拥有 这个变量而区分。 144 | 145 | 类的变量 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。 146 | 147 | 对象的变量 由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。通过一个例子会使这个易于理解。 148 | 149 | ### 使用类与对象的变量 150 | **例11.4 使用类与对象的变量** 151 | 152 | ```python 153 | #!/usr/bin/python 154 | # Filename: objvar.py 155 | 156 | class Person: 157 | '''Represents a person.''' 158 | population = 0 159 | 160 | def __init__(self, name): 161 | '''Initializes the person's data.''' 162 | self.name = name 163 | print '(Initializing %s)' % self.name 164 | 165 | # When this person is created, he/she 166 | # adds to the population 167 | Person.population += 1 168 | 169 | def __del__(self): 170 | '''I am dying.''' 171 | print '%s says bye.' % self.name 172 | 173 | Person.population -= 1 174 | 175 | if Person.population == 0: 176 | print 'I am the last one.' 177 | else: 178 | print 'There are still %d people left.' % Person.population 179 | 180 | def sayHi(self): 181 | '''Greeting by the person. 182 | 183 | Really, that's all it does.''' 184 | print 'Hi, my name is %s.' % self.name 185 | 186 | def howMany(self): 187 | '''Prints the current population.''' 188 | if Person.population == 1: 189 | print 'I am the only person here.' 190 | else: 191 | print 'We have %d persons here.' % Person.population 192 | 193 | swaroop = Person('Swaroop') 194 | swaroop.sayHi() 195 | swaroop.howMany() 196 | 197 | kalam = Person('Abdul Kalam') 198 | kalam.sayHi() 199 | kalam.howMany() 200 | 201 | swaroop.sayHi() 202 | swaroop.howMany() 203 | ``` 204 | 205 | (源文件:[code/objvar.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/objvar.py)) 206 | 207 | ### 输出 208 | 209 | ``` 210 | $ python objvar.py 211 | (Initializing Swaroop) 212 | Hi, my name is Swaroop. 213 | I am the only person here. 214 | (Initializing Abdul Kalam) 215 | Hi, my name is Abdul Kalam. 216 | We have 2 persons here. 217 | Hi, my name is Swaroop. 218 | We have 2 persons here. 219 | Abdul Kalam says bye. 220 | There are still 1 people left. 221 | Swaroop says bye. 222 | I am the last one. 223 | ``` 224 | 225 | ### 它如何工作 226 | 这是一个很长的例子,但是它有助于说明类与对象的变量的本质。这里,population属于Person类,因此是一个类的变量。name变量属于对象(它使用self赋值)因此是对象的变量。 227 | 228 | 观察可以发现__init__方法用一个名字来初始化Person实例。在这个方法中,我们让population增加1,这是因为我们增加了一个人。同样可以发现,self.name的值根据每个对象指定,这表明了它作为对象的变量的本质。 229 | 230 | 记住,你只能使用self变量来参考同一个对象的变量和方法。这被称为 属性参考 。 231 | 232 | 在这个程序中,我们还看到docstring对于类和方法同样有用。我们可以在运行时使用Person.__doc__和Person.sayHi.__doc__来分别访问类与方法的文档字符串。 233 | 234 | 就如同__init__方法一样,还有一个特殊的方法__del__,它在对象消逝的时候被调用。对象消逝即对象不再被使用,它所占用的内存将返回给系统作它用。在这个方法里面,我们只是简单地把Person.population减1。 235 | 236 | 当对象不再被使用时,__del__方法运行,但是很难保证这个方法究竟在 什么时候 运行。如果你想要指明它的运行,你就得使用del语句,就如同我们在以前的例子中使用的那样。 237 | 238 | > **给C++/Java/C#程序员的注释** 239 | 240 | > Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。 241 | 只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevar,Python的名称管理体系会有效地把它作为私有变量。 242 | 这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。 243 | 同样,注意__del__方法与 destructor 的概念类似。 244 | 245 | ## 继承 246 | 面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过 继承 机制。继承完全可以理解成类之间的 类型和子类型 关系。 247 | 248 | 假设你想要写一个程序来记录学校之中的教师和学生情况。他们有一些共同属性,比如姓名、年龄和地址。他们也有专有的属性,比如教师的薪水、课程和假期,学生的成绩和学费。 249 | 250 | 你可以为教师和学生建立两个独立的类来处理它们,但是这样做的话,如果要增加一个新的共有属性,就意味着要在这两个独立的类中都增加这个属性。这很快就会显得不实用。 251 | 252 | 一个比较好的方法是创建一个共同的类称为SchoolMember然后让教师和学生的类 继承 这个共同的类。即它们都是这个类型(类)的子类型,然后我们再为这些子类型添加专有的属性。 253 | 254 | 使用这种方法有很多优点。如果我们增加/改变了SchoolMember中的任何功能,它会自动地反映到子类型之中。例如,你要为教师和学生都增加一个新的身份证域,那么你只需简单地把它加到SchoolMember类中。然而,在一个子类型之中做的改动不会影响到别的子类型。另外一个优点是你可以把教师和学生对象都作为SchoolMember对象来使用,这在某些场合特别有用,比如统计学校成员的人数。一个子类型在任何需要父类型的场合可以被替换成父类型,即对象可以被视作是父类的实例,这种现象被称为多态现象。 255 | 256 | 另外,我们会发现在 重用 父类的代码的时候,我们无需在不同的类中重复它。而如果我们使用独立的类的话,我们就不得不这么做了。 257 | 258 | 在上述的场合中,SchoolMember类被称为 基本类 或 超类 。而Teacher和Student类被称为 导出类 或 子类 。 259 | 260 | 现在,我们将学习一个例子程序。 261 | 262 | ### 使用继承 263 | **例11.5 使用继承** 264 | 265 | ```python 266 | #!/usr/bin/python 267 | # Filename: inherit.py 268 | 269 | class SchoolMember: 270 | '''Represents any school member.''' 271 | def __init__(self, name, age): 272 | self.name = name 273 | self.age = age 274 | print '(Initialized SchoolMember: %s)' % self.name 275 | 276 | def tell(self): 277 | '''Tell my details.''' 278 | print 'Name:"%s" Age:"%s"' % (self.name, self.age), 279 | 280 | class Teacher(SchoolMember): 281 | '''Represents a teacher.''' 282 | def __init__(self, name, age, salary): 283 | SchoolMember.__init__(self, name, age) 284 | self.salary = salary 285 | print '(Initialized Teacher: %s)' % self.name 286 | 287 | def tell(self): 288 | SchoolMember.tell(self) 289 | print 'Salary: "%d"' % self.salary 290 | 291 | class Student(SchoolMember): 292 | '''Represents a student.''' 293 | def __init__(self, name, age, marks): 294 | SchoolMember.__init__(self, name, age) 295 | self.marks = marks 296 | print '(Initialized Student: %s)' % self.name 297 | 298 | def tell(self): 299 | SchoolMember.tell(self) 300 | print 'Marks: "%d"' % self.marks 301 | 302 | t = Teacher('Mrs. Shrividya', 40, 30000) 303 | s = Student('Swaroop', 22, 75) 304 | 305 | print # prints a blank line 306 | 307 | members = [t, s] 308 | for member in members: 309 | member.tell() # works for both Teachers and Students 310 | ``` 311 | 312 | (源文件:[code/inherit.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/inherit.py)) 313 | 314 | ### 输出 315 | 316 | ``` 317 | $ python inherit.py 318 | (Initialized SchoolMember: Mrs. Shrividya) 319 | (Initialized Teacher: Mrs. Shrividya) 320 | (Initialized SchoolMember: Swaroop) 321 | (Initialized Student: Swaroop) 322 | 323 | Name:"Mrs. Shrividya" Age:"40" Salary: "30000" 324 | Name:"Swaroop" Age:"22" Marks: "75" 325 | ``` 326 | 327 | ### 它如何工作 328 | 为了使用继承,我们把基本类的名称作为一个元组跟在定义类时的类名称之后。然后,我们注意到基本类的__init__方法专门使用self变量调用,这样我们就可以初始化对象的基本类部分。这一点十分重要——Python不会自动调用基本类的constructor,你得亲自专门调用它。 329 | 330 | 我们还观察到我们在方法调用之前加上类名称前缀,然后把self变量及其他参数传递给它。 331 | 332 | 注意,在我们使用SchoolMember类的tell方法的时候,我们把Teacher和Student的实例仅仅作为SchoolMember的实例。 333 | 334 | 另外,在这个例子中,我们调用了子类型的tell方法,而不是SchoolMember类的tell方法。可以这样来理解,Python总是首先查找对应类型的方法,在这个例子中就是如此。如果它不能在导出类中找到对应的方法,它才开始到基本类中逐个查找。基本类是在类定义的时候,在元组之中指明的。 335 | 336 | 一个术语的注释——如果在继承元组中列了一个以上的类,那么它就被称作 多重继承 。 337 | 338 | ## 概括 339 | 我们已经研究了类和对象的多个内容以及与它们相关的多个术语。通过本章,你已经了解了面向对象的编程的优点和缺陷。Python是一个高度面向对象的语言,理解这些概念会在将来有助于你进一步深入学习Python。 340 | 341 | 接下来,我们将学习如何处理输入/输出已经如何用Python访问文件。 -------------------------------------------------------------------------------- /book/第10章 解决问题——编写一个Python脚本.md: -------------------------------------------------------------------------------- 1 | 我们已经研究了Python语言的众多内容,现在我们将来学习一下怎么把这些内容结合起来。我们将设计编写一个能够 做 一些确实有用的事情的程序。 2 | 3 | ## 问题 4 | 我提出的问题是: 我想要一个可以为我的所有重要文件创建备份的程序。 5 | 6 | 尽管这是一个简单的问题,但是问题本身并没有给我们足够的信息来解决它。进一步的分析是必需的。例如,我们如何确定该备份哪些文件?备份保存在哪里?我们怎么样存储备份? 7 | 8 | 在恰当地分析了这个问题之后,我们开始设计我们的程序。我们列了一张表,表示我们的程序应该如何工作。对于这个问题,我已经创建了下面这个列表以说明 我 如何让它工作。如果是你设计的话,你可能不会这样来解决问题——每个人都有其做事的方法,这很正常。 9 | 10 | 1. 需要备份的文件和目录由一个列表指定。 11 | 2. 备份应该保存在主备份目录中。 12 | 3. 文件备份成一个zip文件。 13 | 4. zip存档的名称是当前的日期和时间。 14 | 5. 我们使用标准的zip命令,它通常默认地随Linux/Unix发行版提供。Windows用户可以使用Info-Zip程序。注意你可以使用任何地存档命令,只要它有命令行界面就可以了,那样的话我们可以从我们的脚本中传递参数给它。 15 | 16 | ## 解决方案 17 | 当我们基本完成程序的设计,我们就可以编写代码了,它是对我们的解决方案的实施。 18 | 19 | ### 版本一 20 | **例10.1 备份脚本——版本一** 21 | 22 | ```python 23 | #!/usr/bin/python 24 | # Filename: backup_ver1.py 25 | 26 | import os 27 | import time 28 | 29 | # 1. The files and directories to be backed up are specified in a list. 30 | source = ['/home/swaroop/byte', '/home/swaroop/bin'] 31 | # If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that 32 | 33 | # 2. The backup must be stored in a main backup directory 34 | target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using 35 | 36 | # 3. The files are backed up into a zip file. 37 | # 4. The name of the zip archive is the current date and time 38 | target = target_dir + time.strftime('%Y%m%d%H%M%S') + '.zip' 39 | 40 | # 5. We use the zip command (in Unix/Linux) to put the files in a zip archive 41 | zip_command = "zip -qr '%s' %s" % (target, ' '.join(source)) 42 | 43 | # Run the backup 44 | if os.system(zip_command) == 0: 45 | print 'Successful backup to', target 46 | else: 47 | print 'Backup FAILED' 48 | ``` 49 | 50 | (源文件:[code/backup_ver1.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/backup_ver1.py)) 51 | 52 | ### 输出 53 | 54 | ``` 55 | $ python backup_ver1.py 56 | Successful backup to /mnt/e/backup/20041208073244.zip 57 | ``` 58 | 59 | 现在,我们已经处于测试环节了,在这个环节,我们测试我们的程序是否正确工作。如果它与我们所期望的不一样,我们就得调试我们的程序,即消除程序中的 瑕疵 (错误)。 60 | 61 | ### 它如何工作 62 | 接下来你将看到我们如何把 设计 一步一步地转换为 代码 。 63 | 64 | 我们使用了os和time模块,所以我们输入它们。然后,我们在source列表中指定需要备份的文件和目录。目标目录是我们想要存储备份文件的地方,它由target_dir变量指定。zip归档的名称是目前的日期和时间,我们使用time.strftime()函数获得。它还包括.zip扩展名,将被保存在target_dir目录中。 65 | 66 | time.strftime()函数需要我们在上面的程序中使用的那种定制。%Y会被无世纪的年份所替代。%m会被01到12之间的一个十进制月份数替代,其他依次类推。这些定制的详细情况可以在《Python参考手册》中获得。《Python参考手册》包含在你的Python发行版中。注意这些定制与用于print语句的定制(%后跟一个元组)类似(但不完全相同) 67 | 68 | 我们使用加法操作符来 级连 字符串,即把两个字符串连接在一起返回一个新的字符串。通过这种方式,我们创建了目标zip文件的名称。接着我们创建了zip_command字符串,它包含我们将要执行的命令。你可以在shell(Linux终端或者DOS提示符)中运行它,以检验它是否工作。 69 | 70 | zip命令有一些选项和参数。-q选项用来表示zip命令安静地工作。-r选项表示zip命令对目录递归地工作,即它包括子目录以及子目录中的文件。两个选项可以组合成缩写形式-qr。选项后面跟着待创建的zip归档的名称,然后再是待备份的文件和目录列表。我们使用已经学习过的字符串join方法把source列表转换为字符串。 71 | 72 | 最后,我们使用os.system函数 运行 命令,利用这个函数就好像在 系统 中运行命令一样。即在shell中运行命令——如果命令成功运行,它返回0,否则它返回错误号。 73 | 74 | 根据命令的输出,我们打印对应的消息,显示备份是否创建成功。好了,就是这样我们已经创建了一个脚本来对我们的重要文件做备份! 75 | 76 | > **给Windows用户的注释** 77 | 78 | > 你可以把source列表和target目录设置成任何文件和目录名,但是在Windows中你得小心一些。问题是Windows把反斜杠(\)作为目录分隔符,而Python用反斜杠表示转义符! 79 | 所以,你得使用转义符来表示反斜杠本身或者使用自然字符串。例如,使用'C:\\Documents'或r'C:\Documents'而不是'C:\Documents'——你在使用一个不知名的转义符\D! 80 | 81 | 现在我们已经有了一个可以工作的备份脚本,我们可以在任何我们想要建立文件备份的时候使用它。建议Linux/Unix用户使用前面介绍的可执行的方法,这样就可以在任何地方任何时候运行备份脚本了。这被称为软件的实施环节或开发环节。 82 | 83 | 上面的程序可以正确工作,但是(通常)第一个程序并不是与你所期望的完全一样。例如,可能有些问题你没有设计恰当,又或者你在输入代码的时候发生了一点错误,等等。正常情况下,你应该回到设计环节或者调试程序。 84 | 85 | ### 版本二 86 | 第一个版本的脚本可以工作。然而,我们可以对它做些优化以便让它在我们的日常工作中变得更好。这称为软件的维护环节。 87 | 88 | 我认为优化之一是采用更好的文件名机制——使用 时间 作为文件名,而当前的 日期 作为目录名,存放在主备份目录中。这样做的一个优势是你的备份会以等级结构存储,因此它就更加容易管理了。另外一个优势是文件名的长度也可以变短。还有一个优势是采用各自独立的文件夹可以帮助你方便地检验你是否在每一天创建了备份,因为只有在你创建了备份,才会出现那天的目录。 89 | 90 | **例10.2 备份脚本——版本二** 91 | 92 | ```python 93 | #!/usr/bin/python 94 | # Filename: backup_ver2.py 95 | 96 | import os 97 | import time 98 | 99 | # 1. The files and directories to be backed up are specified in a list. 100 | source = ['/home/swaroop/byte', '/home/swaroop/bin'] 101 | # If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that 102 | 103 | # 2. The backup must be stored in a main backup directory 104 | target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using 105 | 106 | # 3. The files are backed up into a zip file. 107 | # 4. The current day is the name of the subdirectory in the main directory 108 | today = target_dir + time.strftime('%Y%m%d') 109 | # The current time is the name of the zip archive 110 | now = time.strftime('%H%M%S') 111 | 112 | # Create the subdirectory if it isn't already there 113 | if not os.path.exists(today): 114 | os.mkdir(today) # make directory 115 | print 'Successfully created directory', today 116 | 117 | # The name of the zip file 118 | target = today + os.sep + now + '.zip' 119 | 120 | # 5. We use the zip command (in Unix/Linux) to put the files in a zip archive 121 | zip_command = "zip -qr '%s' %s" % (target, ' '.join(source)) 122 | 123 | # Run the backup 124 | if os.system(zip_command) == 0: 125 | print 'Successful backup to', target 126 | else: 127 | print 'Backup FAILED' 128 | ``` 129 | 130 | (源文件:[code/backup_ver2.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/backup_ver2.py)) 131 | 132 | ### 输出 133 | 134 | ``` 135 | $ python backup_ver2.py 136 | Successfully created directory /mnt/e/backup/20041208 137 | Successful backup to /mnt/e/backup/20041208/080020.zip 138 | 139 | $ python backup_ver2.py 140 | Successful backup to /mnt/e/backup/20041208/080428.zip 141 | ``` 142 | 143 | ### 它如何工作 144 | 两个程序的大部分是相同的。改变的部分主要是使用os.exists函数检验在主备份目录中是否有以当前日期作为名称的目录。如果没有,我们使用os.mkdir函数创建。 145 | 146 | 注意os.sep变量的用法——这会根据你的操作系统给出目录分隔符,即在Linux、Unix下它是'/',在Windows下它是'\\',而在Mac OS下它是':'。使用os.sep而非直接使用字符,会使我们的程序具有移植性,可以在上述这些系统下工作。 147 | 148 | ### 版本三 149 | 第二个版本在我做较多备份的时候还工作得不错,但是如果有极多备份的时候,我发现要区分每个备份是干什么的,会变得十分困难!例如,我可能对程序或者演讲稿做了一些重要的改变,于是我想要把这些改变与zip归档的名称联系起来。这可以通过在zip归档名上附带一个用户提供的注释来方便地实现。 150 | 151 | **例10.3 备份脚本——版本三(不工作!)** 152 | 153 | ```python 154 | #!/usr/bin/python 155 | # Filename: backup_ver3.py 156 | 157 | import os 158 | import time 159 | 160 | # 1. The files and directories to be backed up are specified in a list. 161 | source = ['/home/swaroop/byte', '/home/swaroop/bin'] 162 | # If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that 163 | 164 | # 2. The backup must be stored in a main backup directory 165 | target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using 166 | 167 | # 3. The files are backed up into a zip file. 168 | # 4. The current day is the name of the subdirectory in the main directory 169 | today = target_dir + time.strftime('%Y%m%d') 170 | # The current time is the name of the zip archive 171 | now = time.strftime('%H%M%S') 172 | 173 | # Take a comment from the user to create the name of the zip file 174 | comment = raw_input('Enter a comment --> ') 175 | if len(comment) == 0: # check if a comment was entered 176 | target = today + os.sep + now + '.zip' 177 | else: 178 | target = today + os.sep + now + '_' + 179 | comment.replace(' ', '_') + '.zip' 180 | 181 | # Create the subdirectory if it isn't already there 182 | if not os.path.exists(today): 183 | os.mkdir(today) # make directory 184 | print 'Successfully created directory', today 185 | 186 | # 5. We use the zip command (in Unix/Linux) to put the files in a zip archive 187 | zip_command = "zip -qr '%s' %s" % (target, ' '.join(source)) 188 | 189 | # Run the backup 190 | if os.system(zip_command) == 0: 191 | print 'Successful backup to', target 192 | else: 193 | print 'Backup FAILED' 194 | ``` 195 | 196 | (源文件:[code/backup_ver3.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/backup_ver3.py)) 197 | 198 | ### 输出 199 | 200 | ``` 201 | $ python backup_ver3.py 202 | File "backup_ver3.py", line 25 203 | target = today + os.sep + now + '_' + 204 | ^ 205 | SyntaxError: invalid syntax 206 | ``` 207 | 208 | ### 它如何(不)工作 209 | 这个程序不工作!Python说有一个语法错误,这意味着脚本不满足Python可以识别的结构。当我们观察Python给出的错误的时候,它也告诉了我们它检测出错误的位置。所以我们从那行开始 调试 我们的程序。 210 | 211 | 通过仔细的观察,我们发现一个逻辑行被分成了两个物理行,但是我们并没有指明这两个物理行属于同一逻辑行。基本上,Python发现加法操作符(+)在那一逻辑行没有任何操作数,因此它不知道该如何继续。记住我们可以使用物理行尾的反斜杠来表示逻辑行在下一物理行继续。所以,我们修正了程序。这被称为修订。 212 | 213 | ### 版本四 214 | 215 | **例10.4 备份脚本——版本四** 216 | 217 | ```python 218 | #!/usr/bin/python 219 | # Filename: backup_ver4.py 220 | 221 | import os 222 | import time 223 | 224 | # 1. The files and directories to be backed up are specified in a list. 225 | source = ['/home/swaroop/byte', '/home/swaroop/bin'] 226 | # If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that 227 | 228 | # 2. The backup must be stored in a main backup directory 229 | target_dir = '/mnt/e/backup/' # Remember to change this to what you will be using 230 | 231 | # 3. The files are backed up into a zip file. 232 | # 4. The current day is the name of the subdirectory in the main directory 233 | today = target_dir + time.strftime('%Y%m%d') 234 | # The current time is the name of the zip archive 235 | now = time.strftime('%H%M%S') 236 | 237 | # Take a comment from the user to create the name of the zip file 238 | comment = raw_input('Enter a comment --> ') 239 | if len(comment) == 0: # check if a comment was entered 240 | target = today + os.sep + now + '.zip' 241 | else: 242 | target = today + os.sep + now + '_' + \ 243 | comment.replace(' ', '_') + '.zip' 244 | # Notice the backslash! 245 | 246 | # Create the subdirectory if it isn't already there 247 | if not os.path.exists(today): 248 | os.mkdir(today) # make directory 249 | print 'Successfully created directory', today 250 | 251 | # 5. We use the zip command (in Unix/Linux) to put the files in a zip archive 252 | zip_command = "zip -qr '%s' %s" % (target, ' '.join(source)) 253 | 254 | # Run the backup 255 | if os.system(zip_command) == 0: 256 | print 'Successful backup to', target 257 | else: 258 | print 'Backup FAILED' 259 | ``` 260 | 261 | (源文件:[code/backup_ver4.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/backup_ver4.py)) 262 | 263 | ### 输出 264 | 265 | ``` 266 | $ python backup_ver4.py 267 | Enter a comment --> added new examples 268 | Successful backup to /mnt/e/backup/20041208/082156_added_new_examples.zip 269 | 270 | $ python backup_ver4.py 271 | Enter a comment --> 272 | Successful backup to /mnt/e/backup/20041208/082316.zip 273 | ``` 274 | 275 | ### 它如何工作 276 | 这个程序现在工作了!让我们看一下版本三中作出的实质性改进。我们使用raw_input函数得到用户的注释,然后通过len函数找出输入的长度以检验用户是否确实输入了什么东西。如果用户只是按了回车(比如这只是一个惯例备份,没有做什么特别的修改),那么我们就如之前那样继续操作。 277 | 278 | 然而,如果提供了注释,那么它会被附加到zip归档名,就在.zip扩展名之前。注意我们把注释中的空格替换成下划线——这是因为处理这样的文件名要容易得多。 279 | 280 | ### 进一步优化 281 | 对于大多数用户来说,第四个版本是一个满意的工作脚本了,但是它仍然有进一步改进的空间。比如,你可以在程序中包含 交互 程度——你可以用-v选项来使你的程序更具交互性。 282 | 283 | 另一个可能的改进是使文件和目录能够通过命令行直接传递给脚本。我们可以通过sys.argv列表来获取它们,然后我们可以使用list类提供的extend方法把它们加到source列表中去。 284 | 285 | 我还希望有的一个优化是使用tar命令替代zip命令。这样做的一个优势是在你结合使用tar和gzip命令的时候,备份会更快更小。如果你想要在Windows中使用这些归档,WinZip也能方便地处理这些.tar.gz文件。tar命令在大多数Linux/Unix系统中都是默认可用的。Windows用户也可以下载安装它。 286 | 287 | 命令字符串现在将称为: 288 | 289 | ```python 290 | tar = 'tar -cvzf %s %s -X /home/swaroop/excludes.txt' % (target, ' '.join(srcdir)) 291 | ``` 292 | 293 | 选项解释如下: 294 | 295 | - -c表示创建一个归档。 296 | 297 | - -v表示交互,即命令更具交互性。 298 | 299 | - -z表示使用gzip滤波器。 300 | 301 | - -f表示强迫创建归档,即如果已经有一个同名文件,它会被替换。 302 | 303 | - -X表示含在指定文件名列表中的文件会被排除在备份之外。例如,你可以在文件中指定*~,从而不让备份包括所有以~结尾的文件。 304 | 305 | > **重要** 306 | 307 | > 最理想的创建这些归档的方法是分别使用zipfile和tarfile。它们是Python标准库的一部分,可以供你使用。使用这些库就避免了使用os.system这个不推荐使用的函数,它容易引发严重的错误。 308 | 然而,我在本节中使用os.system的方法来创建备份,这纯粹是为了教学的需要。这样的话,例子就可以简单到让每个人都能够理解,同时也已经足够用了。 309 | 310 | ## 软件开发过程 311 | 现在,我们已经走过了编写一个软件的各个环节。这些环节可以概括如下: 312 | 313 | 1. 什么(分析) 314 | 2. 如何(设计) 315 | 3. 编写(实施) 316 | 4. 测试(测试与调试) 317 | 5. 使用(实施或开发) 318 | 6. 维护(优化) 319 | 320 | > **重要** 321 | 322 | > 我们创建这个备份脚本的过程是编写程序的推荐方法——进行分析与设计。开始时实施一个简单的版本。对它进行测试与调试。使用它以确信它如预期那样地工作。再增加任何你想要的特性,根据需要一次次重复这个编写-测试-使用的周期。记住“软件是长出来的,而不是建造的”。 323 | 324 | ## 概括 325 | 我们已经学习如何创建我们自己的Python程序/脚本,以及在编写这个程序中所设计到的不同的状态。你可以发现它们在创建你自己的程序的时候会十分有用,让你对Python以及解决问题都变得更加得心应手。 326 | 327 | 接下来,我们将讨论面向对象的编程。 -------------------------------------------------------------------------------- /book/第9章 数据结构.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 数据结构基本上就是——它们是可以处理一些 数据 的 结构 。或者说,它们是用来存储一组相关数据的。 3 | 4 | 在Python中有三种内建的数据结构——列表、元组和字典。我们将会学习如何使用它们,以及它们如何使编程变得简单。 5 | 6 | ## 列表 7 | list是处理一组有序项目的数据结构,即你可以在一个列表中存储一个 序列 的项目。假想你有一个购物列表,上面记载着你要买的东西,你就容易理解列表了。只不过在你的购物表上,可能每样东西都独自占有一行,而在Python中,你在每个项目之间用逗号分割。 8 | 9 | 列表中的项目应该包括在方括号中,这样Python就知道你是在指明一个列表。一旦你创建了一个列表,你可以添加、删除或是搜索列表中的项目。由于你可以增加或删除项目,我们说列表是 可变的 数据类型,即这种类型是可以被改变的。 10 | 11 | ### 对象与类的快速入门 12 | 尽管我一直推迟讨论对象和类,但是现在对它们做一点解释可以使你更好的理解列表。我们会在相应的章节详细探索这个主题。 13 | 14 | 列表是使用对象和类的一个例子。当你使用变量i并给它赋值的时候,比如赋整数5,你可以认为你创建了一个类(类型)int的对象(实例)i。事实上,你可以看一下help(int)以更好地理解这一点。 15 | 16 | 类也有方法,即仅仅为类而定义地函数。仅仅在你有一个该类的对象的时候,你才可以使用这些功能。例如,Python为list类提供了append方法,这个方法让你在列表尾添加一个项目。例如mylist.append('an item')列表mylist中增加那个字符串。注意,使用点号来使用对象的方法。 17 | 18 | 一个类也有域,它是仅仅为类而定义的变量。仅仅在你有一个该类的对象的时候,你才可以使用这些变量/名称。类也通过点号使用,例如mylist.field。 19 | 20 | ### 使用列表 21 | **例9.1 使用列表** 22 | 23 | ```python 24 | #!/usr/bin/python 25 | # Filename: using_list.py 26 | 27 | # This is my shopping list 28 | shoplist = ['apple', 'mango', 'carrot', 'banana'] 29 | 30 | print 'I have', len(shoplist),'items to purchase.' 31 | 32 | print 'These items are:', # Notice the comma at end of the line 33 | for item in shoplist: 34 | print item, 35 | 36 | print '\nI also have to buy rice.' 37 | shoplist.append('rice') 38 | print 'My shopping list is now', shoplist 39 | 40 | print 'I will sort my list now' 41 | shoplist.sort() 42 | print 'Sorted shopping list is', shoplist 43 | 44 | print 'The first item I will buy is', shoplist[0] 45 | olditem = shoplist[0] 46 | del shoplist[0] 47 | print 'I bought the', olditem 48 | print 'My shopping list is now', shoplist 49 | ``` 50 | 51 | (源文件:[code/using_list.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_list.py)) 52 | 53 | ### 输出 54 | 55 | ``` 56 | $ python using_list.py 57 | I have 4 items to purchase. 58 | These items are: apple mango carrot banana 59 | I also have to buy rice. 60 | My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice'] 61 | I will sort my list now 62 | Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice'] 63 | The first item I will buy is apple 64 | I bought the apple 65 | My shopping list is now ['banana', 'carrot', 'mango', 'rice'] 66 | ``` 67 | 68 | ### 它如何工作 69 | 变量shoplist是某人的购物列表。在shoplist中,我们只存储购买的东西的名字字符串,但是记住,你可以在列表中添加 任何种类的对象 包括数甚至其他列表。 70 | 71 | 我们也使用了for..in循环在列表中各项目间递归。从现在开始,你一定已经意识到列表也是一个序列。序列的特性会在后面的章节中讨论。 72 | 73 | 注意,我们在print语句的结尾使用了一个 逗号 来消除每个print语句自动打印的换行符。这样做有点难看,不过确实简单有效。 74 | 75 | 接下来,我们使用append方法在列表中添加了一个项目,就如前面已经讨论过的一样。然后我们通过打印列表的内容来检验这个项目是否确实被添加进列表了。打印列表只需简单地把列表传递给print语句,我们可以得到一个整洁的输出。 76 | 77 | 再接下来,我们使用列表的sort方法来对列表排序。需要理解的是,这个方法影响列表本身,而不是返回一个修改后的列表——这与字符串工作的方法不同。这就是我们所说的列表是 可变的 而字符串是 不可变的 。 78 | 79 | 最后,但我们完成了在市场购买一样东西的时候,我们想要把它从列表中删除。我们使用del语句来完成这个工作。这里,我们指出我们想要删除列表中的哪个项目,而del语句为我们从列表中删除它。我们指明我们想要删除列表中的第一个元素,因此我们使用del shoplist[0](记住,Python从0开始计数)。 80 | 81 | 如果你想要知道列表对象定义的所有方法,可以通过help(list)获得完整的知识。 82 | 83 | ## 元组 84 | 元组和列表十分类似,只不过元组和字符串一样是 不可变的 即你不能修改元组。元组通过圆括号中用逗号分割的项目定义。元组通常用在使语句或用户定义的函数能够安全地采用一组值的时候,即被使用的元组的值不会改变。 85 | 86 | ### 使用元组 87 | **例9.2 使用元组** 88 | 89 | ```python 90 | #!/usr/bin/python 91 | # Filename: using_tuple.py 92 | 93 | zoo = ('wolf', 'elephant', 'penguin') 94 | print 'Number of animals in the zoo is', len(zoo) 95 | 96 | new_zoo = ('monkey', 'dolphin', zoo) 97 | print 'Number of animals in the new zoo is', len(new_zoo) 98 | print 'All animals in new zoo are', new_zoo 99 | print 'Animals brought from old zoo are', new_zoo[2] 100 | print 'Last animal brought from old zoo is', new_zoo[2][2] 101 | ``` 102 | 103 | (源文件:[code/using_tuple.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_tuple.py)) 104 | 105 | ### 输出 106 | 107 | ``` 108 | $ python using_tuple.py 109 | Number of animals in the zoo is 3 110 | Number of animals in the new zoo is 3 111 | All animals in new zoo are ('monkey', 'dolphin', ('wolf', 'elephant', 'penguin')) 112 | Animals brought from old zoo are ('wolf', 'elephant', 'penguin') 113 | Last animal brought from old zoo is penguin 114 | ``` 115 | 116 | ### 它如何工作 117 | 变量zoo是一个元组,我们看到len函数可以用来获取元组的长度。这也表明元组也是一个序列。 118 | 119 | 由于老动物园关闭了,我们把动物转移到新动物园。因此,new_zoo元组包含了一些已经在那里的动物和从老动物园带过来的动物。回到话题,注意元组之内的元组不会失去它的身份。 120 | 121 | 我们可以通过一对方括号来指明某个项目的位置从而来访问元组中的项目,就像我们对列表的用法一样。这被称作 索引 运算符。我们使用new\_zoo[2]来访问new\_zoo中的第三个项目。我们使用new\_zoo[2][2]来访问new_zoo元组的第三个项目的第三个项目。 122 | 123 | 含有0个或1个项目的元组。一个空的元组由一对空的圆括号组成,如myempty = ()。然而,含有单个元素的元组就不那么简单了。你必须在第一个(唯一一个)项目后跟一个逗号,这样Python才能区分元组和表达式中一个带圆括号的对象。即如果你想要的是一个包含项目2的元组的时候,你应该指明singleton = (2 , )。 124 | 125 | > **给Perl程序员的注释** 126 | 127 | > 列表之中的列表不会失去它的身份,即列表不会像Perl中那样被打散。同样元组中的元组,或列表中的元组,或元组中的列表等等都是如此。只要是Python,它们就只是使用另一个对象存储的对象。 128 | 129 | ### 元组与打印语句 130 | 元组最通常的用法是用在打印语句中,下面是一个例子: 131 | 132 | **例9.3 使用元组输出** 133 | 134 | ```python 135 | #!/usr/bin/python 136 | # Filename: print_tuple.py 137 | 138 | age = 22 139 | name = 'Swaroop' 140 | 141 | print '%s is %d years old' % (name, age) 142 | print 'Why is %s playing with that python?' % name 143 | ``` 144 | 145 | (源文件:[code/print_tuple.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/print_tuple.py)) 146 | 147 | ### 输出 148 | 149 | ``` 150 | $ python print_tuple.py 151 | Swaroop is 22 years old 152 | Why is Swaroop playing with that python? 153 | ``` 154 | 155 | ### 它如何工作 156 | print语句可以使用跟着%符号的项目元组的字符串。这些字符串具备定制的功能。定制让输出满足某种特定的格式。定制可以是%s表示字符串或%d表示整数。元组必须按照相同的顺序来对应这些定制。 157 | 158 | 观察我们使用的第一个元组,我们首先使用%s,这对应变量name,它是元组中的第一个项目。而第二个定制是%d,它对应元组的第二个项目age。 159 | 160 | Python在这里所做的是把元组中的每个项目转换成字符串并且用字符串的值替换定制的位置。因此%s被替换为变量name的值,依此类推。 161 | 162 | print的这个用法使得编写输出变得极其简单,它避免了许多字符串操作。它也避免了我们一直以来使用的逗号。 163 | 164 | 在大多数时候,你可以只使用%s定制,而让Python来提你处理剩余的事情。这种方法对数同样奏效。然而,你可能希望使用正确的定制,从而可以避免多一层的检验程序是否正确。 165 | 166 | 在第二个print语句中,我们使用了一个定制,后面跟着%符号后的单个项目——没有圆括号。这只在字符串中只有一个定制的时候有效。 167 | 168 | ## 字典 169 | 字典类似于你通过联系人名字查找地址和联系人详细情况的地址簿,即,我们把键(名字)和值(详细情况)联系在一起。注意,键必须是唯一的,就像如果有两个人恰巧同名的话,你无法找到正确的信息。 170 | 171 | 注意,你只能使用不可变的对象(比如字符串)来作为字典的键,但是你可以不可变或可变的对象作为字典的值。基本说来就是,你应该只使用简单的对象作为键。 172 | 173 | 键值对在字典中以这样的方式标记:d = {key1 : value1, key2 : value2 }。注意它们的键/值对用冒号分割,而各个对用逗号分割,所有这些都包括在花括号中。 174 | 175 | 记住字典中的键/值对是没有顺序的。如果你想要一个特定的顺序,那么你应该在使用前自己对它们排序。 176 | 177 | 字典是dict类的实例/对象。 178 | 179 | ### 使用字典 180 | **例9.4 使用字典** 181 | 182 | ```python 183 | #!/usr/bin/python 184 | # Filename: using_dict.py 185 | 186 | # 'ab' is short for 'a'ddress'b'ook 187 | 188 | ab = { 'Swaroop' : 'swaroopch@byteofpython.info', 189 | 'Larry' : 'larry@wall.org', 190 | 'Matsumoto' : 'matz@ruby-lang.org', 191 | 'Spammer' : 'spammer@hotmail.com' 192 | } 193 | 194 | print "Swaroop's address is %s" % ab['Swaroop'] 195 | 196 | # Adding a key/value pair 197 | ab['Guido'] = 'guido@python.org' 198 | 199 | # Deleting a key/value pair 200 | del ab['Spammer'] 201 | 202 | print '\nThere are %d contacts in the address-book\n' % len(ab) 203 | for name, address in ab.items(): 204 | print 'Contact %s at %s' % (name, address) 205 | 206 | if 'Guido' in ab: # OR ab.has_key('Guido') 207 | print "\nGuido's address is %s" % ab['Guido'] 208 | ``` 209 | 210 | (源文件:[code/using_dict.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/using_dict.py)) 211 | 212 | ### 输出 213 | 214 | ``` 215 | $ python using_dict.py 216 | Swaroop's address is swaroopch@byteofpython.info 217 | 218 | There are 4 contacts in the address-book 219 | 220 | Contact Swaroop at swaroopch@byteofpython.info 221 | Contact Matsumoto at matz@ruby-lang.org 222 | Contact Larry at larry@wall.org 223 | Contact Guido at guido@python.org 224 | 225 | Guido's address is guido@python.org 226 | ``` 227 | 228 | ### 它如何工作 229 | 我们使用已经介绍过的标记创建了字典ab。然后我们使用在列表和元组章节中已经讨论过的索引操作符来指定键,从而使用键/值对。我们可以看到字典的语法同样十分简单。 230 | 231 | 我们可以使用索引操作符来寻址一个键并为它赋值,这样就增加了一个新的键/值对,就像在上面的例子中我们对Guido所做的一样。 232 | 233 | 我们可以使用我们的老朋友——del语句来删除键/值对。我们只需要指明字典和用索引操作符指明要删除的键,然后把它们传递给del语句就可以了。执行这个操作的时候,我们无需知道那个键所对应的值。 234 | 235 | 接下来,我们使用字典的items方法,来使用字典中的每个键/值对。这会返回一个元组的列表,其中每个元组都包含一对项目——键与对应的值。我们抓取这个对,然后分别赋给for..in循环中的变量name和address然后在for-块中打印这些值。 236 | 237 | 我们可以使用in操作符来检验一个键/值对是否存在,或者使用dict类的has_key方法。你可以使用help(dict)来查看dict类的完整方法列表。 238 | 239 | 关键字参数与字典。如果换一个角度看待你在函数中使用的关键字参数的话,你已经使用了字典了!只需想一下——你在函数定义的参数列表中使用的键/值对。当你在函数中使用变量的时候,它只不过是使用一个字典的键(这在编译器设计的术语中被称作 符号表 )。 240 | 241 | ## 序列 242 | 列表、元组和字符串都是序列,但是序列是什么,它们为什么如此特别呢?序列的两个主要特点是索引操作符和切片操作符。索引操作符让我们可以从序列中抓取一个特定项目。切片操作符让我们能够获取序列的一个切片,即一部分序列。 243 | 244 | ### 使用序列 245 | **例9.5 使用序列** 246 | 247 | ```python 248 | #!/usr/bin/python 249 | # Filename: seq.py 250 | 251 | shoplist = ['apple', 'mango', 'carrot', 'banana'] 252 | 253 | # Indexing or 'Subscription' operation 254 | print 'Item 0 is', shoplist[0] 255 | print 'Item 1 is', shoplist[1] 256 | print 'Item 2 is', shoplist[2] 257 | print 'Item 3 is', shoplist[3] 258 | print 'Item -1 is', shoplist[-1] 259 | print 'Item -2 is', shoplist[-2] 260 | 261 | # Slicing on a list 262 | print 'Item 1 to 3 is', shoplist[1:3] 263 | print 'Item 2 to end is', shoplist[2:] 264 | print 'Item 1 to -1 is', shoplist[1:-1] 265 | print 'Item start to end is', shoplist[:] 266 | 267 | # Slicing on a string 268 | name = 'swaroop' 269 | print 'characters 1 to 3 is', name[1:3] 270 | print 'characters 2 to end is', name[2:] 271 | print 'characters 1 to -1 is', name[1:-1] 272 | print 'characters start to end is', name[:] 273 | ``` 274 | 275 | (源文件:[code/seq.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/seq.py)) 276 | 277 | ### 输出 278 | 279 | ``` 280 | $ python seq.py 281 | Item 0 is apple 282 | Item 1 is mango 283 | Item 2 is carrot 284 | Item 3 is banana 285 | Item -1 is banana 286 | Item -2 is carrot 287 | Item 1 to 3 is ['mango', 'carrot'] 288 | Item 2 to end is ['carrot', 'banana'] 289 | Item 1 to -1 is ['mango', 'carrot'] 290 | Item start to end is ['apple', 'mango', 'carrot', 'banana'] 291 | characters 1 to 3 is wa 292 | characters 2 to end is aroop 293 | characters 1 to -1 is waroo 294 | characters start to end is swaroop 295 | ``` 296 | 297 | ### 它如何工作 298 | 首先,我们来学习如何使用索引来取得序列中的单个项目。这也被称作是下标操作。每当你用方括号中的一个数来指定一个序列的时候,Python会为你抓取序列中对应位置的项目。记住,Python从0开始计数。因此,shoplist[0]抓取第一个项目,shoplist[3]抓取shoplist序列中的第四个元素。 299 | 300 | 索引同样可以是负数,在那样的情况下,位置是从序列尾开始计算的。因此,shoplist[-1]表示序列的最后一个元素而shoplist[-2]抓取序列的倒数第二个项目。 301 | 302 | 切片操作符是序列名后跟一个方括号,方括号中有一对可选的数字,并用冒号分割。注意这与你使用的索引操作符十分相似。记住数是可选的,而冒号是必须的。 303 | 304 | 切片操作符中的第一个数(冒号之前)表示切片开始的位置,第二个数(冒号之后)表示切片到哪里结束。如果不指定第一个数,Python就从序列首开始。如果没有指定第二个数,则Python会停止在序列尾。注意,返回的序列从开始位置 开始 ,刚好在 结束 位置之前结束。即开始位置是包含在序列切片中的,而结束位置被排斥在切片外。 305 | 306 | 这样,shoplist[1:3]返回从位置1开始,包括位置2,但是停止在位置3的一个序列切片,因此返回一个含有两个项目的切片。类似地,shoplist[:]返回整个序列的拷贝。 307 | 308 | 你可以用负数做切片。负数用在从序列尾开始计算的位置。例如,shoplist[:-1]会返回除了最后一个项目外包含所有项目的序列切片。 309 | 310 | 使用Python解释器交互地尝试不同切片指定组合,即在提示符下你能够马上看到结果。序列的神奇之处在于你可以用相同的方法访问元组、列表和字符串。 311 | 312 | ## 参考 313 | 当你创建一个对象并给它赋一个变量的时候,这个变量仅仅 参考 那个对象,而不是表示这个对象本身!也就是说,变量名指向你计算机中存储那个对象的内存。这被称作名称到对象的绑定。 314 | 315 | 一般说来,你不需要担心这个,只是在参考上有些细微的效果需要你注意。这会通过下面这个例子加以说明。 316 | 317 | ### 对象与参考 318 | **例9.6 对象与参考** 319 | 320 | ```python 321 | #!/usr/bin/python 322 | # Filename: reference.py 323 | 324 | print 'Simple Assignment' 325 | shoplist = ['apple', 'mango', 'carrot', 'banana'] 326 | mylist = shoplist # mylist is just another name pointing to the same object! 327 | 328 | del shoplist[0] 329 | 330 | print 'shoplist is', shoplist 331 | print 'mylist is', mylist 332 | # notice that both shoplist and mylist both print the same list without 333 | # the 'apple' confirming that they point to the same object 334 | 335 | print 'Copy by making a full slice' 336 | mylist = shoplist[:] # make a copy by doing a full slice 337 | del mylist[0] # remove first item 338 | 339 | print 'shoplist is', shoplist 340 | print 'mylist is', mylist 341 | # notice that now the two lists are different 342 | ``` 343 | 344 | (源文件:[code/reference.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/reference.py)) 345 | 346 | ### 输出 347 | 348 | ``` 349 | $ python reference.py 350 | Simple Assignment 351 | shoplist is ['mango', 'carrot', 'banana'] 352 | mylist is ['mango', 'carrot', 'banana'] 353 | Copy by making a full slice 354 | shoplist is ['mango', 'carrot', 'banana'] 355 | mylist is ['carrot', 'banana'] 356 | ``` 357 | 358 | ### 它如何工作 359 | 大多数解释已经在程序的注释中了。你需要记住的只是如果你想要复制一个列表或者类似的序列或者其他复杂的对象(不是如整数那样的简单 对象 ),那么你必须使用切片操作符来取得拷贝。如果你只是想要使用另一个变量名,两个名称都 参考 同一个对象,那么如果你不小心的话,可能会引来各种麻烦。 360 | 361 | > **给Perl程序员的注释** 362 | 363 | > 记住列表的赋值语句不创建拷贝。你得使用切片操作符来建立序列的拷贝。 364 | 365 | 366 | ## 更多字符串的内容 367 | 我们已经在前面详细讨论了字符串。我们还需要知道什么呢?那么,你是否知道字符串也是对象,同样具有方法。这些方法可以完成包括检验一部分字符串和去除空格在内的各种工作。 368 | 369 | 你在程序中使用的字符串都是str类的对象。这个类的一些有用的方法会在下面这个例子中说明。如果要了解这些方法的完整列表,请参见help(str) 370 | 371 | ### 字符串的方法 372 | **例9.7 字符串的方法** 373 | 374 | ```python 375 | #!/usr/bin/python 376 | # Filename: str_methods.py 377 | 378 | name = 'Swaroop' # This is a string object 379 | 380 | if name.startswith('Swa'): 381 | print 'Yes, the string starts with "Swa"' 382 | 383 | if 'a' in name: 384 | print 'Yes, it contains the string "a"' 385 | 386 | if name.find('war') != -1: 387 | print 'Yes, it contains the string "war"' 388 | 389 | delimiter = '_*_' 390 | mylist = ['Brazil', 'Russia', 'India', 'China'] 391 | print delimiter.join(mylist) 392 | ``` 393 | 394 | (源文件:[code/str_methods.py](http://woodpecker.org.cn/abyteofpython_cn/chinese/code/str_methods.py)) 395 | 396 | ### 输出 397 | 398 | ``` 399 | $ python str_methods.py 400 | Yes, the string starts with "Swa" 401 | Yes, it contains the string "a" 402 | Yes, it contains the string "war" 403 | Brazil_*_Russia_*_India_*_China 404 | ``` 405 | 406 | ### 它如何工作 407 | 这里,我们看到使用了许多字符串方法。startwith方法是用来测试字符串是否以给定字符串开始。in操作符用来检验一个给定字符串是否为另一个字符串的一部分。 408 | 409 | find方法用来找出给定字符串在另一个字符串中的位置,或者返回-1以表示找不到子字符串。str类也有以一个作为分隔符的字符串join序列的项目的整洁的方法,它返回一个生成的大字符串。 410 | 411 | ## 概括 412 | 我们已经详细探讨了多种Python内建的数据结构。这些数据结构将是编写程序时至关重要的部分。 413 | 414 | 现在我们已经掌握了很多Python的基本知识,我们接下来将学习如何设计和编写一个实用的Python程序。 415 | 416 | --------------------------------------------------------------------------------