当前位置: >>
Python3.5.1入门指南中文版(打印版)
Python 3.5.1 入门指南1. 开胃菜..................................................................................................................................................................... 1 2. 使用 Python 解释器 ............................................................................................................................................. 3 2.1. 调用 Python 解释器 .................................................................................................................................. 3 2.1.1. 参数传递........................................................................................................................................... 4 2.1.2. 交互模式........................................................................................................................................... 4 2.2. 解释器及其环境 .......................................................................................................................................... 4 2.2.1. 源程序编码....................................................................................................................................... 4 3. Python 简介 ............................................................................................................................................................ 6 3.1. 将 Python 当做计算器 .............................................................................................................................. 6 3.1.1. 数字................................................................................................................................................... 6 3.1.2. 字符串............................................................................................................................................... 8 3.1.3. 列表................................................................................................................................................. 12 3.2. 编程的第一步............................................................................................................................................ 14 4. 深入 Python 流程控制 ....................................................................................................................................... 16 4.1. if 语句......................................................................................................................................................... 16 4.2. for 语句 ...................................................................................................................................................... 16 4.3. range() 函数 ............................................................................................................................................... 17 4.4. break 和 continue 语句, 以及循环中的 else 子句 .............................................................................. 18 4.5. pass 语句.................................................................................................................................................... 19 4.6. 定义函数.................................................................................................................................................... 19 4.7. 深入 Python 函数定义 ............................................................................................................................ 21 4.7.1. 默认参数值..................................................................................................................................... 21 4.7.2. 关键字参数..................................................................................................................................... 23 4.7.3. 可变参数列表 ................................................................................................................................. 25 4.7.4. 参数列表的分拆 ............................................................................................................................. 25 4.7.5. Lambda 形式 ................................................................................................................................... 26 4.7.6. 文档字符串..................................................................................................................................... 26 4.7.7. 函数注解......................................................................................................................................... 27 4.8. 插曲:编码风格 ........................................................................................................................................ 27 5. 数据结构............................................................................................................................................................... 29 5.1. 关于列表更多的内容 ................................................................................................................................ 29 5.1.1. 把链表当作堆栈使用 ..................................................................................................................... 30 5.1.2. 把链表当作队列使用 ..................................................................................................................... 31 5.1.3. 列表推导式..................................................................................................................................... 31 5.1.4. 嵌套的列表推导式 ......................................................................................................................... 33 5.2. del 语句 ...................................................................................................................................................... 34 5.3. 元组和序列................................................................................................................................................ 35 5.4. 集合............................................................................................................................................................ 36 5.5. 字典............................................................................................................................................................ 37 5.6. 循环技巧.................................................................................................................................................... 38 5.7. 深入条件控制............................................................................................................................................ 39 5.8. 比较序列和其它类型 ................................................................................................................................ 40 6. 模块....................................................................................................................................................................... 41 6.1. 深入模块.................................................................................................................................................... 42 6.1.1. 作为脚本来执行模块 ..................................................................................................................... 43 6.1.2. 模块的搜索路径 ............................................................................................................................. 436.1.3. “编译的” Python 文件 .................................................................................................................... 44 6.2. 标准模块.................................................................................................................................................... 44 6.3. dir() 函数 .................................................................................................................................................... 45 6.4. 包................................................................................................................................................................ 46 6.4.1. 从 * 导入包 ................................................................................................................................... 48 6.4.2. 包内引用......................................................................................................................................... 49 6.4.3. 多重目录中的包 ............................................................................................................................. 49 7. 输入和输出........................................................................................................................................................... 50 7.1. 格式化输出................................................................................................................................................ 50 7.1.1. 旧式的字符串格式化 ..................................................................................................................... 53 7.2. 文件读写.................................................................................................................................................... 53 7.2.1. 文件对象方法 ................................................................................................................................. 54 7.2.2. 使用 json 存储结构化数据 .......................................................................................................... 56 8. 错误和异常........................................................................................................................................................... 58 8.1. 语法错误.................................................................................................................................................... 58 8.2. 异常............................................................................................................................................................ 58 8.3. 异常处理.................................................................................................................................................... 59 8.4. 抛出异常.................................................................................................................................................... 61 8.5. 用户自定义异常 ........................................................................................................................................ 62 8.6. 定义清理行为............................................................................................................................................ 63 8.7. 预定义清理行为 ........................................................................................................................................ 64 9. 类........................................................................................................................................................................... 65 9.1. 术语相关.................................................................................................................................................... 65 9.2. Python 作用域和命名空间 ....................................................................................................................... 65 9.2.1. 作用域和命名空间示例 ................................................................................................................. 67 9.3. 初识类........................................................................................................................................................ 68 9.3.1. 类定义语法..................................................................................................................................... 68 9.3.2. 类对象............................................................................................................................................. 68 9.3.3. 实例对象......................................................................................................................................... 69 9.3.4. 方法对象......................................................................................................................................... 70 9.3.5. 类和实例变量 ................................................................................................................................. 70 9.4. 一些说明.................................................................................................................................................... 72 9.5. 继承............................................................................................................................................................ 73 9.5.1. 多继承............................................................................................................................................. 74 9.6. 私有变量.................................................................................................................................................... 75 9.7. 补充............................................................................................................................................................ 75 9.8. 异常也是类................................................................................................................................................ 76 9.9. 迭代器........................................................................................................................................................ 77 9.10. 生成器...................................................................................................................................................... 78 9.11. 生成器表达式.......................................................................................................................................... 79 10. Python 标准库概览 ............................................................................................................................................ 80 10.1. 操作系统接口.......................................................................................................................................... 80 10.2. 文件通配符.............................................................................................................................................. 80 10.3. 命令行参数.............................................................................................................................................. 81 10.4. 错误输出重定向和程序终止 .................................................................................................................. 81 10.5. 字符串正则匹配...................................................................................................................................... 8110.6. 数学.......................................................................................................................................................... 81 10.7. 互联网访问.............................................................................................................................................. 82 10.8. 日期和时间.............................................................................................................................................. 83 10.9. 数据压缩.................................................................................................................................................. 83 10.10. 性能度量................................................................................................................................................ 83 10.11. 质量控制................................................................................................................................................ 84 10.12. “瑞士军刀” ............................................................................................................................................. 85 11. 标准库浏览 C Part II .......................................................................................................................................... 86 11.1. 输出格式.................................................................................................................................................. 86 11.2. 模板.......................................................................................................................................................... 87 11.3. 使用二进制数据记录布局 ...................................................................................................................... 88 11.4. 多线程...................................................................................................................................................... 88 11.5. 日志.......................................................................................................................................................... 89 11.6. 弱引用...................................................................................................................................................... 90 11.7. 列表工具.................................................................................................................................................. 90 11.8. 十进制浮点数算法 .................................................................................................................................. 92 12. 虚拟环境和包..................................................................................................................................................... 93 12.1. 简介.......................................................................................................................................................... 93 12.2. 创建虚拟环境.......................................................................................................................................... 93 12.3. 使用 pip 管理包..................................................................................................................................... 941. 开胃菜如果你要用计算机做很多工作, 最后你会发现有一些任务你更希望用自动化的方式进行处理。 比如, 你想要在大量的文本文件中执行查找/替换,或者以复杂 的方式对大量的图片进行重命名和整理。 也许你想要编写一个小型的自定义数据库、一个特殊的 GUI 应用程序或一个简单的小游戏。 如果你是一名专业的软件开发者,可能你必须使用几种 C/C++/JAVA 类库,并且发现通常编写/编译 /测试/重新编译的周期是如此漫长。也许你正在为这些类库编写测试用例,但是发现这是一个让人 烦躁的工作。又或者你已经完成 了一个可以使用扩展语言的程序,但你并不想为此重新设计并实现 一套全新的语言。 那么 Python 正是你所需要的语言。 虽然你能够通过编写 Unix shell 脚本或 Windows 批处理文件来处理其中的某些任务, 但 Shell 脚 本更适合移动文件或修改文本数据,并不适合编写 GUI 应用程序或游戏;虽然你能够使用 C/C++/JAVA 编写程序,但即使编写一个简单的 first-draft 程序也有可能耗费大量的开发时间。 相比之下,Python 更易于使用,无论在 Windows、Mac OS X 或 Unix 操作系统上它都会帮助你更 快地完成任务。 虽然 Python 易于使用,但它却是一门完整的编程语言;与 Shell 脚本或批处理文件相比,它为编 写大型程序提供了更多的结构和支持。另一方面,Python 提供了比 C 更多的错误检查,并且作为 一门 高级语言,它内置支持高级的数据结构类型,例如:灵活的数组和字典。因其更多的通用数据 类型,Python 比 Awk 甚至 Perl 都适用于更多问题领域,至少大多数事情在 Python 中与其他语 言同样简单。 Python 允许你将程序分割为不同的模块,以便在其他的 Python 程序中重用。Python 内置提供了 大量的标准模块,你可以将其用作程序的基础,或者作为学习 Python 编程的示例。这些模块提供 了诸如文件 I/O、系统调用、Socket 支持,甚至类似 Tk 的用户图形界面(GUI)工具包接口。 Python 是一门解释型语言,因为无需编译和链接,你可以在程序开发中节省宝贵的时间。Python 解 释器可以交互的使用,这使得试验语言的特性、编写临时程序或在自底向上的程序开发中测试方法 非常容易。你甚至还可以把它当做一个桌面计算器。 Python 让程序编写的紧凑和可读。用 Python 编写的程序通常比同样的 C、C++ 或 Java 程序更短 小,这是因为以下几个原因: * 高级数据结构使你可以在一条语句中表达复杂的操作; * 语句组使用缩进代替开始和结束大括号来组织; * 变量或参数无需声明。 Python 是 可扩展 的:如果你会 C 语言编程便可以轻易地为解释器添加内置函数或模块,或者为 了对性能瓶颈作优化,或者将 Python 程序与只有二进制形式的库(比如某个专业的商业图形库)连接起来。一旦你真正掌握了它,你可以将 Python 解释器集成进某个 C 应用程序,并把它当作那 个程序的扩展或命令行语言。 顺便说一句,这个语言的名字来自于 BBC 的 “Monty Python’s Flying Cirecus” 节目,和爬行 类动物没有任何关系。在文档中引用 Monty Python 的典故不仅可行,而且值得鼓励! 现在你已经为 Python 兴奋不已了吧,大概想要领略一些更多的细节!学习一门语言最好的方法就 是使用它,本指南推荐你边读边使用 Python 解释器练习。 下一节中,我们将解释 Python 解释器的用法。这是很简单的一件事情,但它有助于试验后面的例 子。 本手册剩下的部分将通过示例介绍 Python 语言及系统的诸多特性,开始是简单的语法、数据类型 和表达式,接着介绍函数与模块,最后涉及异常和自定义类这样的高级内容。22. 使用 Python 解释器2.1. 调用 Python 解释器Python 解释器通常被安装在目标机器的 /usr/local/bin/python3.5 目录下。将 /usr/local/bin 目录包含进 Unix shell 的搜索路径里,以确保可以通过输入: python3.5 命令来启动他。[1] 由于 Python 解释器的安装路径是可选的,这也可能是其它路径,你可以联系 安装 Python 的用户或系统管理员确认(例如,/usr/local/python 就是一个常见的选择)。 在 Windows 机器上,Python 通常安装在 C:\Python35 位置,当然你可以在运行安装向导时修改此 值。要想把此目录添加到你的 PATH 环境变量中,你可以在 DOS 窗口中输入以下命令: set path=%path%;C:\python35 通常你可以在主窗口输入一个文件结束符(Unix 系统是 Control-D,Windows 系统是 Control-Z) 让解释器以 0 状态码退出。如果那没有作用,你可以通过输入 quit() 命令退出解释器。 Python 解释器具有简单的行编辑功能。在 Unix 系统上,任何 Python 解释器都可能已经添加了 GNU readline 库支持,这样就具备了精巧的交互编辑和历史记录等功能。在 Python 主窗口中输入 Control-P 可能是检查是否支持命令行编辑的最简单的方法。如果发出嘟嘟声(计算机扬声器), 则说明你可以使用命令行编辑功能;更多快捷键的介绍请参考 交互式输入行编辑历史回溯。如果没 有任何声音,或者显示 ^P 字符,则说明命令行编辑功能不可用;你只能通过退格键从当前行删除 已键入的字符并重新输入。 Python 解释器有些操作类似 Unix shell:当使用终端设备(tty)作为标准输入调用时,它交互的 解释并执行命令;当使用文件名参数或以文件作为标准输入调用时,它读取文件并将文件作为 脚本 执行。 第二种启动 Python 解释器的方法是 python -c command [arg] ...,这种方法可以在 命令行 执 行 Python 语句,类似于 shell 中的 -c 选项。由于 Python 语句通常会包含空格或其他特殊 shell 字符,一般建议将 命令 用单引号包裹起来。 有一些 Python 模块也可以当作脚本使用。你可以使用 python -m module [arg] ... 命令调用它 们,这类似在命令行中键入完整的路径名执行 模块 源文件一样。 使用脚本文件时,经常会运行脚本然后进入交互模式。这也可以通过在脚本之前加上 -i 参数来实 现。32.1.1. 参数传递调用解释器时,脚本名和附加参数传入一个名为 sys.argv 的字符串列表。你能够获取这个列表通 过执行 import sys,列表的长度大于等于 1;没有给定脚本和参数时,它至少也有一个元素: sys.argv[0] 此时为空字符串。 脚本名指定为 '-' (表示标准输入) 时, sys.argv[0] 被设定为 '-', 使用 -c 指令 时,sys.argv[0] 被设定为 '-c'。使用 -m 模块 参数时,sys.argv[0] 被设定为指 定模块的全名。-c 指令 或者 -m 模块 之后的参数不会被 Python 解释器的选项处理机制所截获, 而是留在 sys.argv 中,供脚本命令操作。2.1.2. 交互模式从 tty 读取命令时,我们称解释器工作于 交互模式。这种模式下它根据主提示符来执行,主提示 符通常标识为三个大于号(&&&);继续的部分被称为 从属提示符,由三个点标识(...)。在第一行之 前,解释器打印欢迎信息、版本号和授权提示: $ python3.5 Python 3.5 (default, Mar 16 :04) [GCC 4.8.2] on linux Type &help&, ©right&, &credits& or &license& for more information. &&& 输入多行结构时需要从属提示符了,例如,下面这个 if 语句: &&& the_world_is_flat = 1 &&& if the_world_is_flat: ... print(&Be careful not to fall off!&) ... Be careful not to fall off! 关于交互模式更多的内容,请参见 交互模式。2.2. 解释器及其环境 2.2.1. 源程序编码默认情况下,Python 源文件是 UTF-8 编码。在此编码下,全世界大多数语言的字符可以同时用在 字符串、标识符和注释中 ― 尽管 Python 标准库仅使用 ASCII 字符做为标识符,这只是任何可移 植代码应该遵守的约定。如果要正确的显示所有的字符,你的编辑器必须能识别出文件是 UTF-8 编 码,并且它使用的字体能支持文件中所有的字符。 你也可以为源文件指定不同的字符编码。为此,在 #! 行(首行)后插入至少一行特殊的注释行来 定义源文件的编码:4# -*- coding: encoding -*通过此声明,源文件中所有的东西都会被当做用 encoding 指代的 UTF-8 编码对待。在 Python 库 参考手册 codecs 一节中你可以找到一张可用的编码列表。 例如,如果你的编辑器不支持 UTF-8 编码的文件,但支持像 Windows-1252 的其他一些编码,你可 以定义: # -*- coding: cp-1252 -*这样就可以在源文件中使用 Windows-1252 字符集中的所有字符了。这个特殊的编码注释必须在文 件中的 第一或第二 行定义。 Footnotes[1] 在 Unix 系统上,Python 3.X 解释器默认未被安装成名为 python 的命令,所以它不会与同时安装在系统中的 Python 2.x 命令冲突。53. Python 简介下面的例子中,输入和输出分别由大于号和句号提示符( &&& 和 ... )标注:如果想重现这些例 子,就要在解释器的提示符后,输入(提示符后面的)那些不包含提示符的代码行。需要注意的是 在练习中遇到的从属提示符表示你需要在最后多输入一个空行,解释器才能知道这是一个多行命令 的结束。 本手册中的很多示例――包括那些带有交互提示符的――都含有注释。Python 中的注释以 # 字符 起始,直至实际的行尾(译注――这里原作者用了 physical line 以表示实际的换行而非编辑器的 自动换行)。注释可以从行首开始,也可以在空白或代码之后,但是不出现在字符串中。文本字符 串中的 # 字符仅仅表示 # 。代码中的注释不会被 Python 解释,录入示例的时候可以忽略它们。 如下示例: # this is the first comment spam = 1 # and this is the second comment # ... and now a third! text = &# This is not a comment because it's inside quotes.&3.1. 将 Python 当做计算器我们来尝试一些简单的 Python 命令。启动解释器然后等待主提示符 &&& 出现(不需要很久)。3.1.1. 数字解释器表现得就像一个简单的计算器:可以向其录入一些表达式,它会给出返回值。表达式语法很 直白:运算符 +,-,* 和 / 与其它语言一样(例如:Pascal 或 C);括号 (()) 用于分组。例如: &&& 4 &&& 20 &&& 5.0 &&& 1.6 2 + 2 50 - 5*6 (50 - 5*6) / 4 8 / 5 # division always returns a floating point number整数(例如,2, 4, 20 )的类型是 int,带有小数部分的数字(例如,5.0, 1.6)的类型是 float。 在本教程的后面我们会看到更多关于数字类型的内容。 除法(/)永远返回一个浮点数。如要使用 floor 除法 并且得到整数结果(丢掉任何小数部分),你 可以使用 // 运算符;要计算余数你可以使用 % &&& 17 / 3 # classic division returns a float65.667 &&& &&& 17 // 3 # floor division discards the fractional part 5 &&& 17 % 3 # the % operator returns the remainder of the division 2 &&& 5 * 3 + 2 # result * divisor + remainder 17 通过 Python,还可以使用 ** 运算符计算幂乘方 [1]: &&& 5 ** 2 # 5 squared 25 &&& 2 ** 7 # 2 to the power of 7 128 等号( '=' )用于给变量赋值。赋值之后,在下一个提示符之前不会有任何结果显示: &&& width = 20 &&& height = 5*9 &&& width * height 900 变量在使用前必须 “定义”(赋值),否则会出错: &&& # try to access an ... n Traceback (most recent File &&stdin&&, line NameError: name 'n' is undefined variable call last): 1, in &module& not defined浮点数有完整的支持;整数和浮点数的混合计算中,整数会被转换为浮点数: &&& 3 * 3.75 / 1.5 7.5 &&& 7.0 / 2 3.5 交互模式中,最近一个表达式的值赋给变量 _。这样我们就可以把它当作一个桌面计算器,很方便 的用于连续计算,例如: &&& tax = &&& price &&& price 12.5625 &&& price 113. / 100 = 100.50 * tax + _7&&& round(_, 2) 113.06 此变量对于用户是只读的。不要尝试给它赋值 ―― 你只会创建一个独立的同名局部变量,它屏蔽 了系统内置变量的魔术效果。 除了 int 和 float,Python 还支持其它数字类型,例如 Decimal 和 Fraction。Python 还内建支 持 复数 ,使用后缀 j 或 J 表示虚数部分(例如,3+5j)。3.1.2. 字符串相比数值,Python 也提供了可以通过几种不同方式表示的字符串。它们可以用单引号 ('...') 或 双引号 (&...&) 标识 [2]。\ 可以用来转义引号: &&& 'spam eggs' # single quotes 'spam eggs' &&& 'doesn\'t' # use \' to escape the single quote... &doesn't& &&& &doesn't& # ...or use double quotes instead &doesn't& &&& '&Yes,& he said.' '&Yes,& he said.' &&& &\&Yes,\& he said.& '&Yes,& he said.' &&& '&Isn\'t,& she said.' '&Isn\'t,& she said.' 在交互式解释器中,输出的字符串会用引号引起来,特殊字符会用反斜杠转义。虽然可能和输入看 上去不太一样,但是两个字符串是相等的。如果字符串中只有单引号而没有双引号,就用双引号引 用,否则用单引号引用。print() 函数生成可读性更好的输出, 它会省去引号并且打印出转义后的 特殊字符: &&& '&Isn\'t,& she said.' '&Isn\'t,& she said.' &&& print('&Isn\'t,& she said.') &Isn't,& she said. &&& s = 'First line.\nSecond line.' # \n means newline &&& s # without print(), \n is included in the output 'First line.\nSecond line.' &&& print(s) # with print(), \n produces a new line First line. Second line. 如果你前面带有 \ 的字符被当作特殊字符,你可以使用 原始字符串,方法是在第一个引号前面加 上一个 r:8&&& print('C:\some\name') # here \n means newline! C:\some ame &&& print(r'C:\some\name') # note the r before the quote C:\some\name 字符串文本能够分成多行。一种方法是使用三引号:&&&...&&& 或者 '''...'''。行尾换行符会被 自动包含到字符串中,但是可以在行尾加上 \ 来避免这个行为。下面的示例: 可以使用反斜杠为 行结尾的连续字符串,它表示下一行在逻辑上是本行的后续内容: print(&&&\ Usage: thingy [OPTIONS] -h -H hostname &&&)Display this usage message Hostname to connect to将生成以下输出(注意,没有开始的第一行): Usage: thingy [OPTIONS] -h -H hostnameDisplay this usage message Hostname to connect to字符串可以由 + 操作符连接(粘到一起),可以由 * 表示重复: &&& # 3 times 'un', followed by 'ium' &&& 3 * 'un' + 'ium' 'unununium' 相邻的两个字符串文本自动连接在一起。: &&& 'Py' 'thon' 'Python' 它只用于两个字符串文本,不能用于字符串表达式: &&& prefix = 'Py' &&& prefix 'thon' # can't concatenate a variable and a string literal ... SyntaxError: invalid syntax &&& ('un' * 3) 'ium' ... SyntaxError: invalid syntax 如果你想连接多个变量或者连接一个变量和一个字符串文本,使用 +: &&& prefix + 'thon' 'Python'9这个功能在你想切分很长的字符串的时候特别有用: &&& text = ('Put several strings within parentheses ' 'to have them joined together.') &&& text 'Put several strings within parentheses to have them joined together.' 字符串也可以被截取(检索)。类似于 C ,字符串的第一个字符索引为 0 。Python 没有单独的字符 类型;一个字符就是一个简单的长度为 1 的字符串。: &&& word = 'Python' &&& word[0] # character in position 0 'P' &&& word[5] # character in position 5 'n' 索引也可以是负数,这将导致从右边开始计算。例如: &&& word[-1] 'n' &&& word[-2] 'o' &&& word[-6] 'P' # last character # second-last character请注意 -0 实际上就是 0,所以它不会导致从右边开始计算。 除了索引,还支持 切片。索引用于获得单个字符,切片 让你获得一个子字符串: &&& word[0:2] 'Py' &&& word[2:5] 'tho' # characters from position 0 (included) to 2 (excluded) # characters from position 2 (included) to 5 (excluded)注意,包含起始的字符,不包含末尾的字符。这使得 s[:i] + s[i:] 永远等于 s: &&& word[:2] + word[2:] 'Python' &&& word[:4] + word[4:] 'Python' 切片的索引有非常有用的默认值;省略的第一个索引默认为零,省略的第二个索引默认为切片的字 符串的大小。: &&& word[:2] 'Py' &&& word[4:] # character from the beginning to position 2 (excluded) # characters from position 4 (included) to the end10'on' &&& word[-2:] # characters from the second-last (included) to the end 'on' 有个办法可以很容易地记住切片的工作方式:切片时的索引是在两个字符 之间 。左边第一个字符 的索引为 0,而长度为 n 的字符串其最后一个字符的右界索引为 n。例如: +---+---+---+---+---+---+ | P | y | t | h | o | n | +---+---+---+---+---+---+ 0 1 2 3 4 5 6 -6 -5 -4 -3 -2 -1 文本中的第一行数字给出字符串中的索引点 0...6。 第二行给出相应的负索引。 切片是从 i 到 j 两 个数值标示的边界之间的所有字符。 对于非负索引,如果上下都在边界内,切片长度就是两个索引之差。例如,word[1:3] 是 2 。 试图使用太大的索引会导致错误: &&& word[42] # the word only has 6 characters Traceback (most recent call last): File &&stdin&&, line 1, in &module& IndexError: string index out of range Python 能够优雅地处理那些没有意义的切片索引:一个过大的索引值(即下标值大于字符串实际长 度)将被字符串实际长度所代替,当上边界比下边界大时(即切片左值大于右值)就返回空字符串: &&& word[4:42] 'on' &&& word[42:] '' Python 字符串不可以被更改 ― 它们是 不可变的 。因此,赋值给字符串索引的位置会导致错误: &&& word[0] = 'J' ... TypeError: 'str' object does not support item assignment &&& word[2:] = 'py' ... TypeError: 'str' object does not support item assignment 如果你需要一个不同的字符串,你应该创建一个新的: &&& 'J' + word[1:] 'Jython' &&& word[:2] + 'py'11'Pypy' 内置函数 len() 返回字符串长度: &&& s = 'supercalifragilisticexpialidocious' &&& len(s) 343.1.3. 列表Python 有几个 复合 数据类型,用于表示其它的值。最通用的是 list (列表) ,它可以写作中括 号之间的一列逗号分隔的值。列表的元素不必是同一类型: &&& squares = [1, 4, 9, 16, 25] &&& squares [1, 4, 9, 16, 25] 就像字符串(以及其它所有内建的 序列 类型)一样,列表可以被索引和切片: &&& 1 &&& 25 &&& [9, squares[0] squares[-1] squares[-3:] 16, 25] # slicing returns a new list # indexing returns the item所有的切片操作都会返回一个包含请求的元素的新列表。这意味着下面的切片操作返回列表一个新 的(浅)拷贝副本: &&& squares[:] [1, 4, 9, 16, 25] 列表也支持连接这样的操作: &&& squares + [36, 49, 64, 81, 100] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 不像 不可变的 字符串,列表是 可变的,它允许修改元素: &&& &&& 64 &&& &&& [1, cubes = [1, 8, 27, 65, 125] # something's wrong here 4 ** 3 # the cube of 4 is 64, not 65! cubes[3] = 64 # replace the wrong value cubes 8, 27, 64, 125]12你还可以使用 append() 方法 (后面我们会看到更多关于列表的方法的内容)在列表的末尾添加新 的元素: &&& &&& &&& [1, cubes.append(216) # add the cube of 6 cubes.append(7 ** 3) # and the cube of 7 cubes 8, 27, 64, 125, 216, 343]也可以对切片赋值,此操作可以改变列表的尺寸,或清空它: &&& letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] &&& letters ['a', 'b', 'c', 'd', 'e', 'f', 'g'] &&& # replace some values &&& letters[2:5] = ['C', 'D', 'E'] &&& letters ['a', 'b', 'C', 'D', 'E', 'f', 'g'] &&& # now remove them &&& letters[2:5] = [] &&& letters ['a', 'b', 'f', 'g'] &&& # clear the list by replacing all the elements with an empty list &&& letters[:] = [] &&& letters [] 内置函数 len() 同样适用于列表: &&& letters = ['a', 'b', 'c', 'd'] &&& len(letters) 4 允许嵌套列表(创建一个包含其它列表的列表),例如: &&& a = ['a', 'b', 'c'] &&& n = [1, 2, 3] &&& x = [a, n] &&& x [['a', 'b', 'c'], [1, 2, 3]] &&& x[0] ['a', 'b', 'c'] &&& x[0][1] 'b'133.2. 编程的第一步当然,我们可以使用 Python 完成比二加二更复杂的任务。例如,我们可以写一个生成 菲波那契 子 序列的程序,如下所示: &&& ... ... &&& ... ... ... 1 1 2 3 5 8 # Fibonacci series: # the sum of two elements defines the next a, b = 0, 1 while b & 10: print(b) a, b = b, a+b这个例子介绍了几个新功能。?第一行包括了一个 多重赋值:变量 a 和 b 同时获得了新的值 0 和 1 最后一行又使用了一 次。 在这个演示中,变量赋值前,右边首先完成计算。右边的表达式从左到右计算。?条件(这里是 b & 10 )为 true 时, while 循环执行。在 Python 中,类似于 C,任何非 零整数都是 true;0 是 false 条件也可以是字符串或列表,实际上可以是任何序列; 所有长度不为零的是 true,空序列是 false。示例中的测试是一个简单的比较。标准比较操 作符与 C 相同: & , & , == , &=, &= 和 !=。?循环 体 是 缩进 的:缩进是 Python 是 Python 组织Z句的方法。Python (还)不提供集成 的行编辑功能,所以你要为每一个缩进行输入 TAB 或空格。 实践中建议你找个文本编辑来录入复杂的 Python 程序,大多数文本编辑器提供自动缩进。 交互式录入复合语句时,必须在最后输入一个空行来标识结束(因为解释器没办法猜测你输 入的哪一行是最后一行) , 需要 注意的是同一个语句块中的语句块必须缩进同样数量的空白。?关键字 print() 语句输出给定表达式的值。它控制多个表达式和字符串输出为你想要字符串 (就像我们在前面计算器的例子中那样)。 字符串打印时不用引号包围,每两个子项之间插入空间,所以你可以把格式弄得很漂亮,像 这样: &&& i = 256*25614&&& print('The value of i is', i) The value of i is 65536 用一个逗号结尾就可以禁止输出换行: &&& a, b = 0, 1 &&& while b & 1000: ... print(b, end=',') ... a, b = b, a+b ... 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987, Footnotes[1] [2] 因为 ** 的优先级高于 -,所以 -3**2 将解释为 -(3**2) 且结果为 -9。为了避免这点并得到 9,你可以使用 (-3)**2。 与其它语言不同,特殊字符例如 \n 在单引号('...')和双引号(&...&)中具有相同的含义。两者唯一的区别是在单引 号中,你不需要转义 & (但你必须转义 \' ),反之亦然。154. 深入 Python 流程控制除了前面介绍的 while 语句,Python 还从其它语言借鉴了一些流程控制功能,并有所改变。4.1. if 语句也许最有名的是 if 语句。例如: &&& x = int(input(&Please enter an integer: &)) Please enter an integer: 42 &&& if x & 0: ... x = 0 ... print('Negative changed to zero') ... elif x == 0: ... print('Zero') ... elif x == 1: ... print('Single') ... else: ... print('More') ... More 可能会有零到多个 elif 部分,else 是可选的。关键字 ‘elif‘ 是 ’else if’ 的缩写,这个 可以有效地避免过深的缩进。 if ... elif ... elif ... 序列用于替代其它语言中的 switch 或 case 语句。4.2. for 语句Python 中的 for 语句和 C 或 Pascal 中的略有不同。通常的循环可能会依据一个等差数值步进过 程(如 Pascal),或由用户来定义迭代步骤和中止条件(如 C ),Python 的 for 语句依据任意 序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代。例如(没有暗指): &&& # Measure some strings: ... words = ['cat', 'window', 'defenestrate'] &&& for w in words: ... print(w, len(w)) ... cat 3 window 6 defenestrate 12 在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果 你想要修改你迭代的序列(例如,复制选择项),你可以迭代它的复本。使用切割标识就可以很方 便的做到这一点:16&&& for w in words[:]: # Loop over a slice copy of the entire list. ... if len(w) & 6: ... words.insert(0, w) ... &&& words ['defenestrate', 'cat', 'window', 'defenestrate']4.3. range() 函数如果你需要一个数值序列,内置函数 range() 会很方便,它生成一个等差级数链表: &&& for i in range(5): ... print(i) ... 0 1 2 3 4 range(10) 生成了一个包含 10 个值的链表,它用链表的索引值填充了这个长度为 10 的列表,所 生成的链表中不包括范围中的结束值。也可以让 range() 操作从另一个数值开始,或者可以指定一 个不同的步进值(甚至是负数,有时这也被称为 “步长”): range(5, 10) 5 through 9 range(0, 10, 3) 0, 3, 6, 9 range(-10, -100, -30) -10, -40, -70 需要迭代链表索引的话,如下所示结合使 用 range() 和 len() &&& a = ['Mary', 'had', 'a', 'little', 'lamb'] &&& for i in range(len(a)): ... print(i, a[i]) ... 0 Mary 1 had 2 a 3 little 4 lamb 不过,这种场合可以方便的使用 enumerate(),请参见 循环技巧。17如果你只是打印一个序列的话会发生奇怪的事情: &&& print(range(10)) range(0, 10) 在不同方面 range() 函数返回的对象表现为它是一个列表,但事实上它并不是。当你迭代它时,它 是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不真正构造列表。 我们称此类对象是 可迭代的,即适合作为那些期望从某些东西中获得连续项直到结束的函数或结构 的一个目标 (参数) 。 我们已经见过的 for 语句就是这样一个迭代器。 list() 函数是另外一个 ( 迭 代器 ),它从可迭代(对象)中创建列表: &&& list(range(5)) [0, 1, 2, 3, 4] 稍后我们会看到更多返回可迭代(对象)和以可迭代(对象)作为参数的函数。4.4. break 和 continue 语句, 以及循环中的 else 子句break 语句和 C 中的类似,用于跳出最近的一级 for 或 while 循环。 循环可以有一个 else 子句;它在循环迭代完整个列表(对于 for )或执行条件为 false (对于 while )时执行,但循环被 break 中止的情况下不会执行。以下搜索素数的示例程序演示了这个子 句: &&& for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print(n, 'equals', x, '*', n//x) ... break ... else: ... # loop fell through without finding a factor ... print(n, 'is a prime number') ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3 (Yes, 这是正确的代码。看仔细:else 语句是属于 for 循环之中, 不是 if 语句。)18与循环一起使用时, else 子句与 try 语句的 else 子句比与 if 语句的具有更多的共同点: try 语 句的 else 子句在未出现异常时运行, 循环的 else 子句在未出现 break 时运行。 更多关于 try 语 句和异常的内容,请参见 异常处理。 continue 语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代: &&& for num in range(2, 10): ... if num % 2 == 0: ... print(&Found an even number&, num) ... continue ... print(&Found a number&, num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 94.5. pass 语句pass 语句什么也不做。它用于那些语法上必须要有什么语句,但程序什么也不做的场合,例如: &&& while True: ... pass # Busy-wait for keyboard interrupt (Ctrl+C) ... 这通常用于创建最小结构的类: &&& class MyEmptyClass: ... pass ... 另一方面,pass 可以在创建新代码时用来做函数或控制体的占位符。可以让你在更抽象的级别上思 考。pass 可以默默的被忽视: &&& def initlog(*args): ... pass # Remember to implement this! ...4.6. 定义函数我们可以创建一个用来生成指定边界的斐波那契数列的函数:19&&& ... ... ... ... ... ... ... &&& ... 0 1def fib(n): # write Fibonacci series up to n &&&Print a Fibonacci series up to n.&&& a, b = 0, 1 while a & n: print(a, end=' ') a, b = b, a+b print() # Now call the function we just defined: fib( 3 5 8 13 21 34 55 89 144 233 377 610 987 1597关键字 def 引入了一个函数 定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句 从下一行开始,必须是缩进的。 函数体的第一行语句可以是可选的字符串文本,这个字符串是函数的文档字符串,或者称为 docstring。(更多关于 docstrings 的信息请参考 文档字符串) 有些工具通过 docstrings 自动 生成在线的或可打印的文档,或者让用户通过代码交互浏览;在你的代码中包含 docstrings 是一 个好的实践,让它成为习惯吧。 函数 调用 会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存 储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局 符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用 global 语句命名), 尽管他们可以被引用。 函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是 一个对象 引用 ,而不是该对象的值)。[1] 一个函数被另一个函数调用时,一个新的局部符号表 在调用过程中被创建。 一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释 器认定为 用户自定义函数 的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当 做函数使用。这可以作为通用的重命名机制: &&& fib &function fib at 10042ed0& &&& f = fib &&& f(100) 0 1 1 2 3 5 8 13 21 34 55 89 如果你使用过其他语言,你可能会反对说:fib 不是一个函数,而是一个方法,因为它并不返回任 何值。事实上,没有 return 语句的函数确实会返回一个值,虽然是一个相当令人厌烦的值(指 None )。这个值被称为 None (这是一个内建名称)。如果 None 值是唯一被书写的值,那么在写 的时候通常会被解释器忽略(即不输出任何内容)。如果你确实想看到这个值的输出内容,请使用 print() 函数: &&& fib(0) &&& print(fib(0))20None 定义一个返回斐波那契数列数字列表的函数,而不是打印它,是很简单的: &&& ... ... ... ... ... ... ... ... &&& &&& [0, def fib2(n): # return Fibonacci series up to n &&&Return a list containing the Fibonacci series up to n.&&& result = [] a, b = 0, 1 while a & n: result.append(a) # see below a, b = b, a+b return result f100 = fib2(100) # call it f100 # write the result 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]和以前一样,这个例子演示了一些新的 Python 功能:?return 语句从函数中返回一个值,不带表达式的 return 返回 None。 过程结束后也会返回 None。?语句 result.append(b) 称为链表对象 result 的一个 方法。方法是一个“属于”某个对象 的函数,它被命名为 obj.methodename,这里的 obj 是某个对象(可能是一个表达式), methodename 是某个在该对象类型定义中的方法的命名。 不同的类型定义不同的方法。不同类型可能有同样名字的方法,但不会混淆。(当你定义自 己的对象类型和方法时,可能会出现这种情况,class 的定义方法详见 类 )。示例中演示 的 append() 方法由链表对象定义,它向链表中加入一个新元素。在示例中它等同于 result = result + [a],不过效率更高。4.7. 深入 Python 函数定义在 Python 中,你也可以定义包含若干参数的函数。这里有三种可用的形式,也可以混合使用。4.7.1. 默认参数值最常用的一种形式是为一个或多个参数指定默认值。这会创建一个可以使用比定义时允许的参数更 少的参数调用的函数,例如: def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = input(prompt) if ok in ('y', 'ye', 'yes'):21return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries & 0: raise OSError('uncooperative user') print(complaint) 这个函数可以通过几种不同的方式调用:?只给出必要的参数: ask_ok('Do you really want to quit?')?给出一个可选的参数: ask_ok('OK to overwrite the file?', 2)?或者给出所有的参数: ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')这个例子还介绍了 in 关键字。它测定序列中是否包含某个确定的值。 默认值在函数 定义 作用域被解析,如下所示: i = 5 def f(arg=i): print(arg) i = 6 f() 将会输出 5。 重要警告: 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者 大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数: def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print(f(3))22这将输出: [1] [1, 2] [1, 2, 3] 如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数: def f(a, L=None): if L is None: L = [] L.append(a) return L4.7.2. 关键字参数函数可以通过 关键字参数 的形式来调用,形如 keyword = value。例如,以下的函数: def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print(&-- This parrot wouldn't&, action, end=' ') print(&if you put&, voltage, &volts through it.&) print(&-- Lovely plumage, the&, type) print(&-- It's&, state, &!&) 接受一个必选参数 (voltage) 以及三个可选参数 (state, action, 和 type)。可以用以下的任一 方法调用: parrot(1000) parrot(voltage=1000) parrot(voltage=1000000, action='VOOOOOM') parrot(action='VOOOOOM', voltage=1000000) parrot('a million', 'bereft of life', 'jump') parrot('a thousand', state='pushing up the daisies') 不过以下几种调用是无效的: parrot() parrot(voltage=5.0, 'dead') parrot(110, voltage=220) parrot(actor='John Cleese') # # # # required argument missing non-keyword argument after a keyword argument duplicate value for the same argument unknown keyword argument # # # # # # 1 1 2 2 3 1 positional argument keyword argument keyword arguments keyword arguments positional arguments positional, 1 keyword在函数调用中,关键字的参数必须跟随在位置参数的后面。传递的所有关键字参数必须与函数接受 的某个参数相匹配 (例如 actor 不是 parrot 函数的有效参数),它们的顺序并不重要。这也包 括非可选参数(例如 parrot(voltage=1000) 也是有效的)。任何参数都不可以多次赋值。下面的 示例由于这种限制将失败:23&&& def function(a): ... pass ... &&& function(0, a=0) Traceback (most recent call last): File &&stdin&&, line 1, in ? TypeError: function() got multiple values for keyword argument 'a' 引入一个形如 **name 的参数时,它接收一个字典(参见 Mapping Types ― dict ),该字典包含 了所有未出现在形式参数列表中的关键字参数。这里可能还会组合使用一个形如 *name (下一小节 详细介绍) 的形式参数,它接收一个元组(下一节中会详细介绍),包含了所有没有出现在形式参 数列表中的参数值( *name 必须在 **name 之前出现)。 例如,我们这样定义一个函数: def cheeseshop(kind, *arguments, **keywords): print(&-- Do you have any&, kind, &?&) print(&-- I'm sorry, we're all out of&, kind) for arg in arguments: print(arg) print(&-& * 40) keys = sorted(keywords.keys()) for kw in keys: print(kw, &:&, keywords[kw]) 它可以像这样调用: cheeseshop(&Limburger&, &It's very runny, sir.&, &It's really very, VERY runny, sir.&, shopkeeper=&Michael Palin&, client=&John Cleese&, sketch=&Cheese Shop Sketch&) 当然它会按如下内容打印: -- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch 注意在打印关键字参数之前,通过对关键字字典 keys() 方法的结果进行排序,生成了关键字参数 名的列表;如果不这样做,打印出来的参数的顺序是未定义的。244.7.3. 可变参数列表最后, 一个最不常用的选择是可以让函数调用可变个数的参数。 这些参数被包装进一个元组 (参见 元 组和序列 )。在这些可变个数的参数之前,可以有零到多个普通的参数: def write_multiple_items(file, separator, *args): file.write(separator.join(args)) 通常,这些 可变 参数是参数列表中的最后一个,因为它们将把所有的剩余输入参数传递给函数。 任何出现在 *args 后的参数是关键字参数,这意味着,他们只能被用作关键字,而不是位置参数: &&& def concat(*args, sep=&/&): ... return sep.join(args) ... &&& concat(&earth&, &mars&, &venus&) 'earth/mars/venus' &&& concat(&earth&, &mars&, &venus&, sep=&.&) 'earth.mars.venus'4.7.4. 参数列表的分拆另有一种相反的情况: 当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参 数值。这时候你要把已有的列表拆开来。例如内建函数 range() 需要要独立的 start,stop 参数。 你可以在调用函数时加一个 * 操作符来自动把参数列表拆开: &&& [3, &&& &&& [3, list(range(3, 6)) 4, 5] args = [3, 6] list(range(*args)) 4, 5] # normal call with separate arguments# call with arguments unpacked from a list以同样的方式,可以使用 ** 操作符分拆关键字参数为字典: &&& def parrot(voltage, state='a stiff', action='voom'): ... print(&-- This parrot wouldn't&, action, end=' ') ... print(&if you put&, voltage, &volts through it.&, end=' ') ... print(&E's&, state, &!&) ... &&& d = {&voltage&: &four million&, &state&: &bleedin' demised&, &action&: &VOOM&} &&& parrot(**d) -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !254.7.5. Lambda 形式出于实际需要,有几种通常在函数式编程语言例如 Lisp 中出现的功能加入到了 Python。通过 lambda 关键字,可以创建短小的匿名函数。这里有一个函数返回它的两个参数的和: lambda a, b: a+b。 Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。 语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外 部作用域引用变量: &&& ... ... &&& &&& 42 &&& 43 def make_incrementor(n): return lambda x: x + n f = make_incrementor(42) f(0) f(1)上面的示例使用 lambda 表达式返回一个函数。另一个用途是将一个小函数作为参数传递: &&& pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] &&& pairs.sort(key=lambda pair: pair[1]) &&& pairs [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]4.7.6. 文档字符串这里介绍的文档字符串的概念和格式。 第一行应该是关于对象用途的简介。简短起见,不用明确的陈述对象名或类型,因为它们可以从别 的途径了解到(除非这个名字碰巧就是描述这个函数操作的动词)。这一行应该以大写字母开头, 以句号结尾。 如果文档字符串有多行,第二行应该空出来,与接下来的详细描述明确分隔。接下来的文档应该有 一或多段描述对象的调用约定、边界效应等。 Python 的解释器不会从多行的文档字符串中去除缩进,所以必要的时候应当自己清除缩进。这符合 通常的习惯。第一行之后的第一个非空行决定了整个文档的缩进格式。 (我们不用第一行是因为它 通常紧靠着起始的引号,缩进格式显示的不清楚。)留白“相当于”是字符串的起始缩进。每一行 都不应该有缩进,如果有缩进的话,所 有的留白都应该清除掉。留白的长度应当等于扩展制表符的 宽度(通常是 8 个空格)。 以下是一个多行文档字符串的示例: &&& def my_function(): ... &&&Do nothing, but document it.26... ... No, really, it doesn't do anything. ... &&& ... pass ... &&& print(my_function.__doc__) Do nothing, but document it. No, really, it doesn't do anything.4.7.7. 函数注解函数注解 是关于用户自定义的函数的完全可选的、随意的元数据信息。无论 Python 本身或者标准 库中都没有使用函数注解;本节只是描述了语法。第三方的项目是自由地为文档,类型检查,以及 其它用途选择函数注解。 注解是以字典形式存储在函数的 __annotations__ 属性中,对函数的其它部分没有任何影响。参数 注解(Parameter annotations)是定义在参数名称的冒号后面,紧随着一个用来表示注解的值得表 达式。返回注释(Return annotations)是定义在一个 -& 后面,紧随着一个表达式,在冒号与 -& 之间。下面的示例包含一个位置参数,一个关键字参数,和没有意义的返回值注释: &&& def f(ham: 42, eggs: int = 'spam') -& &Nothing to see here&: ... print(&Annotations:&, f.__annotations__) ... print(&Arguments:&, ham, eggs) ... &&& f('wonderful') Annotations: {'eggs': &class 'int'&, 'return': 'Nothing to see here', 'ham': 42} Arguments: wonderful spam4.8. 插曲:编码风格此时你已经可以写一些更长更复杂的 Python 程序,是时候讨论一下 编码风格 了。大多数语言可 以写(或者更明白的说, 格式化 )作几种不同的风格。有些比其它的更好读。让你的代码对别人 更易读是个好想法,养成良好的编码风格对此很有帮助。 对于 Python,PEP 8 引入了大多数项目遵循的风格指导。它给出了一个高度可读,视觉友好的编码 风格。每个 Python 开发者都应该读一下,大多数要点都会对你有帮助:?使用 4 空格缩进,而非 TAB 在小缩进(可以嵌套更深)和大缩进(更易读)之间,4 空格是一个很好的折中。TAB 引发了 一些混乱,最好弃用?折行以确保其不会超过 79 个字符27这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码文件? ? ? ? ?使用空行分隔函数和类,以及函数中的大块代码 可能的话,注释独占一行 使用文档字符串 把空格放到操作符两边,以及逗号后面,但是括号里侧不加空格:a = f(1, 2) + g(3, 4) 统一函数和类命名 推荐类名用 驼峰命名, 函数和方法名用 小写_和_下划线。总是用 self 作为方法的第一个 参数(关于类和方法的知识详见 初识类 )? ?不要使用花哨的编码, 如果你的代码的目的是要在国际化环境。 Python 的默认情况下, UTF-8, 甚至普通的 ASCII 总是工作的最好 同样,也不要使用非 ASCII 字符的标识符,除非是不同语种的会阅读或者维护代码。285. 数据结构本章详细讨论了你已经学过的一些知识,同样也添加了一些新内容。5.1. 关于列表更多的内容Python 的列表数据类型包含更多的方法。这里是所有的列表对象方法: list.append(x) 把一个元素添加到链表的结尾,相当于 a[len(a):] = [x]。 list.extend(L) 将一个给定列表中的所有元素都添加到另一个列表中,相当于 a[len(a):] = L。 list.insert(i, x) 在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会插入到整个链表之前,而 a.insert(len(a), x) 相当于 a.append(x)。 list.remove(x) 删除链表中值为 x 的第一个元素。如果没有这样的元素,就会返回一个错误。 list.pop([i]) 从链表的指定位置删除元素,并将其返回。如果没有指定索引,a.pop() 返回最后一个元素。 元素随即从链表中被删除(方法中 i 两边的方括号表示这个参数是可选的,而不是要求你输 入一对方括号,你会经常在 Python 库参考手册中遇到这样的标记)。 list.clear() 从列表中删除所有元素。相当于 del a[:]。 list.index(x) 返回链表中第一个值为 x 的元素的索引。如果没有匹配的元素就会返回一个错误。 list.count(x) 返回 x 在链表中出现的次数。 list.sort() 对链表中的元素就地进行排序。29list.reverse() 就地倒排链表中的元素。 list.copy() 返回列表的一个浅拷贝。等同于 a[:]。 下面这个示例演示了链表的大部分方法: &&& a = [66.25, 333, 333, 1, 1234.5] &&& print(a.count(333), a.count(66.25), a.count('x')) 2 1 0 &&& a.insert(2, -1) &&& a.append(333) &&& a [66.25, 333, -1, 333, 1, 3] &&& a.index(333) 1 &&& a.remove(333) &&& a [66.25, -1, 333, 1, 3] &&& a.reverse() &&& a [333, , 333, -1, 66.25] &&& a.sort() &&& a [-1, 1, 66.25, 333, 333, 1234.5] &&& a.pop() 1234.5 &&& a [-1, 1, 66.25, 333, 333] 也许大家会发现像 insert, remove 或者 sort 这些修改列表的方法没有打印返回值C它们返回 None。 [1] 在 python 中对所有可变的数据类型这是统一的设计原则。5.1.1. 把链表当作堆栈使用链表方法使得链表可以很方便的做为一个堆栈来使用,堆栈作为特定的数据结构,最先进入的元素 最后一个被释放(后进先出)。用 append() 方法可以把一个元素添加到堆栈顶。用不指定索引的 pop() 方法可以把一个元素从堆栈顶释放出来。例如: &&& &&& &&& &&& stack = [3, 4, 5] stack.append(6) stack.append(7) stack30[3, &&& 7 &&& [3, &&& 6 &&& 5 &&& [3,4, 5, 6, 7] stack.pop() stack 4, 5, 6] stack.pop() stack.pop() stack 4]5.1.2. 把链表当作队列使用你也可以把链表当做队列使用,队列作为特定的数据结构,最先进入的元素最先释放(先进先出)。 不过,列表这样用效率不高。相对来说从列表末尾添加和弹出很快;在头部插入和弹出很慢(因为, 为了一个元素,要移动整个列表中的所有元素)。 要实现队列,使用 collections.deque,它为在首尾两端快速插入和删除而设计。例如: &&& from collections import deque &&& queue = deque([&Eric&, &John&, &Michael&]) &&& queue.append(&Terry&) # Terry arrives &&& queue.append(&Graham&) # Graham arrives &&& queue.popleft() # The first to arrive now leaves 'Eric' &&& queue.popleft() # The second to arrive now leaves 'John' &&& queue # Remaining queue in order of arrival deque(['Michael', 'Terry', 'Graham'])5.1.3. 列表推导式列表推导式为从序列中创建列表提供了一个简单的方法。普通的应用程式通过将一些操作应用于序 列的每个成员并通过返回的元素创建列表,或者通过满足特定条件的元素创建子序列。 例如, 假设我们创建一个 squares 列表, 可以像下面方式: &&& &&& ... ... &&& [0, squares = [] for x in range(10): squares.append(x**2) squares 1, 4, 9, 16, 25, 36, 49, 64, 81]31注意这个 for 循环中的被创建(或被重写)的名为 x 的变量在循环完毕后依然存在。使用如下方法, 我们可以计算 squares 的值而不会产生任何的副作用: squares = list(map(lambda x: x**2, range(10))) 或者,等价于: squares = [x**2 for x in range(10)] 上面这个方法更加简明且易读. 列表推导式由包含一个表达式的括号组成,表达式后面跟随一个 for 子句,之后可以有零或多个 for 或 if 子句。结果是一个列表,由表达式依据其后面的 for 和 if 子句上下文计算而来的结果 构成。 例如,如下的列表推导式结合两个列表的元素,如果元素之间不相等的话: &&& [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] 等同于: &&& combs = [] &&& for x in [1,2,3]: ... for y in [3,1,4]: ... if x != y: ... combs.append((x, y)) ... &&& combs [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] 值得注意的是在上面两个方法中的 for 和 if 语句的顺序。 如果想要得到一个元组(例如,上面例子中的 (x, y)),必须要加上括号: &&& vec = [-4, -2, 0, 2, 4] &&& # create a new list with the values doubled &&& [x*2 for x in vec] [-8, -4, 0, 4, 8] &&& # filter the list to exclude negative numbers &&& [x for x in vec if x &= 0] [0, 2, 4] &&& # apply a function to all the elements &&& [abs(x) for x in vec] [4, 2, 0, 2, 4] &&& # call a method on each element &&& freshfruit = [' banana', ' loganberry ', 'passion fruit']32&&& [weapon.strip() for weapon in freshfruit] ['banana', 'loganberry', 'passion fruit'] &&& # create a list of 2-tuples like (number, square) &&& [(x, x**2) for x in range(6)] [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] &&& # the tuple must be parenthesized, otherwise an error is raised &&& [x, x**2 for x in range(6)] File &&stdin&&, line 1, in ? [x, x**2 for x in range(6)] ^ SyntaxError: invalid syntax &&& # flatten a list using a listcomp with two 'for' &&& vec = [[1,2,3], [4,5,6], [7,8,9]] &&& [num for elem in vec for num in elem] [1, 2, 3, 4, 5, 6, 7, 8, 9] 列表推导式可使用复杂的表达式和嵌套函数: &&& from math import pi &&& [str(round(pi, i)) for i in range(1, 6)] ['3.1', '3.14', '3.142', '3.1416', '3.14159']5.1.4. 嵌套的列表推导式列表解析中的第一个表达式可以是任何表达式,包括列表解析。 考虑下面由三个长度为 4 的列表组成的 3x4 矩阵: &&& matrix = [ ... [1, 2, 3, 4], ... [5, 6, 7, 8], ... [9, 10, 11, 12], ... ] 现在,如果你想交换行和列,可以用嵌套的列表推导式: &&& [[row[i] for row in matrix] for i in range(4)] [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] 像前面看到的,嵌套的列表推导式是对 for 后面的内容进行求值,所以上例就等价于: &&& transposed = [] &&& for i in range(4): ... transposed.append([row[i] for row in matrix]) ... &&& transposed33[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] 反过来说,如下也是一样的: &&& transposed = [] &&& for i in range(4): ... # the following 3 lines implement the nested listcomp ... transposed_row = [] ... for row in matrix: ... transposed_row.append(row[i]) ... transposed.append(transposed_row) ... &&& transposed [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] 在实际中,你应该更喜欢使用内置函数组成复杂流程语句。对此种情况 zip() 函数将会做的更好: &&& list(zip(*matrix)) [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)] 更多关于本行中使用的星号的说明,参考 参数列表的分拆。5.2. del 语句有个方法可以从列表中按给定的索引而不是值来删除一个子项: del 语句。它不同于有返回值的 pop() 方法。语句 del 还可以从列表中删除切片或清空整个列表(我们以前介绍过一个方法是将空 列表赋值给列表的切片)。例如: &&& &&& &&& [1, &&& &&& [1, &&& &&& [] a = [-1, 1, 66.25, 333, 333, 1234.5] del a[0] a 66.25, 333, 333, 1234.5] del a[2:4] a 66.25, 1234.5] del a[:] adel 也可以删除整个变量: &&& del a 此后再引用命名 a 会引发错误(直到另一个值赋给它为止)。我们在后面的内容中可以看到 del 的 其它用法。345.3. 元组和序列我们知道链表和字符串有很多通用的属性, 例如索引和切割操作。 它们是 序列 类型 (参见 Sequence Types ― list, tuple, range )中的两种。因为 Python 是一个在不停进化的语言,也可能会加 入其它的序列类型,这里介绍另一种标准序列类型: 元组 。 一个元组由数个逗号分隔的值组成,例如: &&& t = 1, 'hello!' &&& t[0] 12345 &&& t (1, 'hello!') &&& # Tuples may be nested: ... u = t, (1, 2, 3, 4, 5) &&& u ((1, 'hello!'), (1, 2, 3, 4, 5)) &&& # Tuples are immutable: ... t[0] = 88888 Traceback (most recent call last): File &&stdin&&, line 1, in &module& TypeError: 'tuple' object does not support item assignment &&& # but they can contain mutable objects: ... v = ([1, 2, 3], [3, 2, 1]) &&& v ([1, 2, 3], [3, 2, 1]) 如你所见,元组在输出时总是有括号的,以便于正确表达嵌套结构。在输入时可以有或没有括号, 不过经常括号都是必须的(如果元组是一个更大的表达式的一部分)。不能给元组的一个独立的元 素赋值(尽管你可以通过联接和切割来模拟)。还可以创建包含可变对象的元组,例如链表。 虽然元组和列表很类似, 它们经常被用来在不同的情况和不同的用途。 元组有很多用途。 例如 (x, y) 坐标对,数据库中的员工记录等等。元组就像字符串, 不可变的。通常包含不同种类的元素并通过 分拆(参阅本节后面的内容) 或索引访问(如果是 namedtuples,甚至可以通过属性)。列表是 可 变的 ,它们的元素通常是相同类型的并通过迭代访问。 一个特殊的问题是构造包含零个或一个元素的元组: 为了适应这种情况, 语法上有一些额外的改变。 一对空的括号可以创建空元组;要创建一个单元素元组可以在值后面跟一个逗号(在括号中放入一 个单值不够明确)。丑陋,但是有效。例如: &&& &&& &&& 0 &&& 1 empty = () singleton = 'hello', len(empty) len(singleton)# &-- note trailing comma35&&& singleton ('hello',) 语句 t = 1, 'hello!' 是 元组封装 (tuple packing)的一个例子:值 12345 , 54321 和 'hello!' 被封装进元组。其逆操作可能是这样: &&& x, y, z = t 这个调用等号右边可以是任何线性序列,称之为 序列拆封 非常恰当。序列拆封要求左侧的变量数 目与序列的元素个数相同。要注意的是可变参数(multiple assignment )其实只是元组封装和序 列拆封的一个结合。5.4. 集合Python 还包含了一个数据类型 ―― set (集合)。集合是一个无序不重复元素的集。基本功能包 括关系测试和消除重复元素。集合对象还支持 union(联合),intersection(交),difference (差)和 sysmmetric difference(对称差集)等数学运算。 大括号或 set() 函数可以用来创建集合。注意:想要创建空集合,你必须使用 set() 而不是 {}。 后者用于创建空字典,我们在下一节中介绍的一种数据结构。 以下是一个简单的演示: &&& basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} &&& print(basket) # show that duplicates have been removed {'orange', 'banana', 'pear', 'apple'} &&& 'orange' in basket # fast membership testing True &&& 'crabgrass' in basket False &&& # ... &&& a &&& b &&& a {'a', &&& a {'r', &&& a {'a', &&& a {'a', &&& a {'r', Demonstrate set operations on unique letters from two words = set('abracadabra') = set('alacazam') # unique letters in a 'r', - b 'd', | b 'c', & b 'c'} ^ b 'd', 'b', 'c', 'd'} # letters in a but not in b 'b'} # letters in either a or b 'r', 'd', 'b', 'm', 'z', 'l'} # letters in both a and b # letters in a or b but not both 'b', 'm', 'z', 'l'}36类似 列表推导式,这里有一种集合推导式语法: &&& a = {x for x in 'abracadabra' if x not in 'abc'} &&& a {'r', 'd'}5.5. 字典另一个非常有用的 Python 内建数据类型是 字典 (参见 Mapping Types ― dict )。字典在某些 语言中可能称为 联合内存 ( associative memories )或 联合数组 ( associative arrays )。 序列是以连续的整数为索引,与此不同的是,字典以 关键字 为索引,关键字可以是任意不可变类 型,通常用字符串或数值。如果元组中只包含字符串和数字,它可以做为关键字,如果它直接或间 接的包含了可变对象,就不能当做关键字。不能用链表做关键字,因为链表可以用索引、切割或者 append() 和 extend() 等方法改变。 理解字典的最佳方式是把它看做无序的键: 值对 (key:value 对)集合,键必须是互不相同的(在 同一个字典之内)。一对大括号创建一个空的字典: {} 。初始化链表时,在大括号内放置一组逗 号分隔的键:值对,这也是字典输出的方式。 字典的主要操作是依据键来存储和析取值。也可以用 del 来删除键:值对(key:value)。如果你 用一个已经