Python编程:从入门到实践

埃里克·马瑟斯

前言

  • 游戏、数据可视化和Web应用程序
  • Python是一种效率极高的语言:相比于众多其他的语言,使用Python编写时,程序包含的代码行更少。Python的语法也有助于创建整洁的代码:相比其他语言,使用Python编写的代码更容易阅读、调试和扩展。

致谢

  • 感谢我的父亲,感谢他在我很小的时候就向我介绍编程,而且一点都不担心我破坏他的设备。

第一部分 基础知识

  • 要想脱离初级程序员的阵容,跻身于中级程序员的行列,测试代码是你必须掌握的基本技能之一。

第1章 起步

  • 当前,有两个不同的Python版本:Python 2和较新的Python 3。
  • 只要代码清单中包含三个尖括号(如❶所示),就意味着输出来自终端会话。
  • Python是一种跨平台的编程语言,这意味着它能够运行在所有主要的操作系统中。
  • Geany是一款简单的文本编辑器:它易于安装;让你能够直接运行几乎所有的程序(而无需通过终端来运行);使用不同的颜色来显示代码,以突出代码语法;
  • 4.在终端会话中运行Python代码
  • 要关闭Python解释器,可按Ctrl+D或执行命令exit()。
  • Sublime Text是一款简单的文本编辑器:它在OS X中易于安装
  • 1.2.3 在Windows系统中搭建Python编程环境
  • 要关闭该终端会话,可按Ctrl+Z,再按回车键,也可执行命令exit()。
  • 如果没有看到这样的输出,请检查你输入的每个字符。你是不是将print的首字母大写了?是不是遗漏了引号或括号?编程语言对语法的要求非常严格,只要你没有严格遵守语法,就会出错。如果代码都正确,这个程序也不能正确地运行,请参阅下一节。
  • 程序存在严重的错误时,Python将显示traceback。
  • 只要能清晰地说明你要做什么、尝试了哪些方法及其结果,就很可能有人能够帮到你。
  • 在命令窗口中,要在文件系统中导航,可使用终端命令cd;要列出当前目录中的所有文件,可使用命令dir(表示目录, directory)。
  • 现在请花点时间描绘三个你想创建的程序。

第2章 变量和简单数据类型

  • 第2章 变量和简单数据类型
  • 变量名只能包含字母、数字和下划线。变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message
  • 可调用函数str(),它让Python将非字符串值表示为字符串:
  • 在Python中,注释用井号(#)标识。井号后面的内容都会被Python解释器忽略,
  • 编写注释的主要目的是阐述代码要做什么,以及是如何做的。
  • 作为新手,最值得养成的习惯之一是,在代码中编写清晰、简洁的注释。
  • Python社区的理念都包含在Tim Peters撰写的“Python之禅”中。要获悉这些有关编写优秀Python代码的指导原则,只需在解释器中执行命令import this。
  • 不要企图编写完美无缺的代码;先编写行之有效的代码,再决定是对其做进一步改进,还是转而去编写新代码。
  • 在本章中,你学习了:如何使用变量;如何创建描述性变量名以及如何消除名称错误和语法错误;字符串是什么,以及如何使用小写、大写和首字母大写方式显示字符串;使用空白来显示整洁的输出,以及如何剔除字符串中多余的空白;如何使用整数和浮点数;使用数值数据时需要注意的意外行为。你还学习了如何编写说明性注释,让代码对你和其他人来说更容易理解。最后,你了解了让代码尽可能简单的理念。
  • 在本章中,你学习了:如何使用变量;如何创建描述性变量名以及如何消除名称错误和语法错误;字符串是什么,以及如何使用小写、大写和首字母大写方式显示字符串;使用空白来显示整洁的输出,以及如何剔除字符串中多余的空白;如何使用整数和浮点数;使用数值数据时需要注意的意外行为。你还学习了如何编写说明性注释,让代码对你和其他人来说更容易理解。最后,你了解了让代码尽可能简单的理念。

第3章 列表简介

  • Python为访问最后一个列表元素提供了一种特殊语法。通过将索引指定为-1,可让Python返回最后一个列表元素:

第4章 操作列表

  • Python将不能修改的值称为不可变的,而不可变的列表被称为元组。
  • 虽然不能修改元组的元素,但可以给存储元组的变量赋值。
  • 相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
  • PEP 8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。
  • 很多Python程序员都建议每行不超过80字符。
  • 要将程序的不同部分分开,可使用空行。
  • 空行不会影响代码的运行,但会影响代码的可读性。Python解释器根据水平缩进情况来解读代码,但不关心垂直间距。
  • 在本章中,你学习了:如何高效地处理列表中的元素;如何使用for循环遍历列表,Python如何根据缩进来确定程序的结构以及如何避免一些常见的缩进错误;如何创建简单的数字列表,以及可对数字列表执行的一些操作;如何通过切片来使用列表的一部分和复制列表。你还学习了元组(它对不应变化的值提供了一定程度的保护),以及在代码变得越来越复杂时如何设置格式,使其易于阅读。

第5章 if语句

  • 要判断特定的值是否已包含在列表中,可使用关键字in。
  • 在条件测试的格式设置方面,PEP 8提供的唯一建议是,在诸如==、>=和<=等比较运算符两边各添加一个空格,例如,if age < 4:要比if age<4:好。

第6章 字典

  • 在Python中,字典是一系列键—值对。每个键都与一个值相关联,你可以使用键来访问与之相关联的值。与键相关联的值可以是数字、字符串、列表乃至字典。事实上,可将任何Python对象用作字典中的值。
  • for语句的第二部分包含字典名和方法items()(见❶),它返回一个键—值对列表。
  • 为剔除重复项,可使用集合(set)。集合类似于列表,但每个元素都必须是独一无二的

第7章 用户输入和while循环

  • 在要求很多条件都满足才继续运行的程序中,可定义一个变量,用于判断整个程序是否处于活动状态。这个变量被称为标志,充当了程序的交通信号灯。
  • for循环是一种遍历列表的有效方式,但在for循环中不应修改列表,否则将导致Python难以跟踪其中的元素。要在遍历列表的同时对其进行修改,可使用while循环。

第8章 函数

  • 使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的形参。这让Python依然能够正确地解读位置实参。
  • 函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值。在函数中,可使用return语句将值返回到调用函数的代码行。返回值让你能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。
  • 形参名*toppings中的星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中。
  • 将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。import语句允许在当前运行的程序文件中使用模块中的代码。
  • 编写函数时,需要牢记几个细节。应给函数指定描述性名称,且只在其中使用小写字母和下划线。
  • 给形参指定默认值时,等号两边不要有空格:
  • 所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
  • importmodule_namefrommodule_name importfunction_namefrommodule_name importfunction_name as fnimportmodule_name asmnfrommodule_name import *
  • 类将函数和数据整洁地封装起来,让你能够灵活而高效地使用它们。

第9章 类

  • 根据约定,在Python中,首字母大写的名称指的是类。这个类定义中的括号是空的,因为我们要从空白创建这个类。
  • 一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
  • Python标准库是一组模块,安装的Python都包含它。
  • 类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。

第10章 文件和异常

  • 关键字with在不再需要访问文件后将其关闭。在这个程序中,注意到我们调用了open(),但没有调用close();你也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。
  • 处的方法readlines()从文件中读取每一行,并将其存储在一个列表中;接下来,该列表被存储到变量lines中;在with代码块外,我们依然可以使用这个变量
  • 在变量pi_string存储的字符串中,包含原来位于每行左边的空格,为删除这些空格,可使用strip()而不是rstrip():
  • 可使用方法replace()将字符串中的特定单词都替换为另一个单词。
  • 第二个实参('w')告诉Python,我们要以写入模式打开这个文件。打开文件时,可指定读取模式('r')、写入模式('w')、附加模式('a')或让你能够读取和写入文件的模式('r+')
  • Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
  • 函数write()不会在你写入的文本末尾添加换行符
  • 要让每个字符串都单独占一行,需要在write()语句中包含换行符:
  • 我们打开文件时指定了实参’a',以便将内容附加到文件末尾,而不是覆盖文件原来的内容
  • 如果try代码块中的代码运行起来没有问题,Python将跳过except代码块;如果try代码块中的代码导致了错误,Python将查找这样的except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。
  • 错误是执行除法运算的代码行导致的,因此我们需要将它放到try-except代码块中。这个示例还包含一个else代码块;依赖于try代码块成功执行的代码都应放到else代码块中:
  • 方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
  • Python有一个pass语句,可在代码块中使用它来让Python什么都不要做:
  • pass语句还充当了占位符,它提醒你在程序的某个地方什么都没有做,并且以后也许要在这里做些什么。
  • 模块json让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。
  • 函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象。
  • 通常使用文件扩展名.json来指出文件存储的数据为JSON格式
  • json.load()将这个列表读取到内存中
  • 你经常会遇到这样的情况:代码能够正确地运行,但可做进一步的改进——将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。重构让代码更清晰、更易于理解、更容易扩展。
  • 将代码划分为一系列完成具体工作的函数。这样的过程被称为重构
  • 考虑到现在使用了一个函数,我们删除了注释,转而使用一个文档字符串来指出程序是做什么的

第11章 测试代码

  • Python标准库中的模块unittest提供了代码测试工具。单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
  • 方法名必须以test_打头,这样它才会在我们运行test_name_function.py时自动运行。
  • unittest.TestCase类包含方法setUp(),让我们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法。这样,在你编写的每个测试方法中都可使用在方法setUp()中创建的对象了。
  • unittest.TestCase类包含方法setUp(),让我们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase类中包含了方法setUp(), Python将先运行它,再运行各个以test_打头的方法。
  • 存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。

第12章 武装飞船

  • Pygame,这是一组功能强大而有趣的模块,可用于管理图形、动画乃至声音,让你能够更轻松地开发复杂的游戏。
  • 游戏《外星人入侵》将包含很多不同的文件,因此请在你的系统中新建一个文件夹,并将其命名为alien_invasion。请务必将这个项目的所有文件都存储到这个文件夹中,这样相关的import语句才能正确地工作。
  • 开发大型项目时,做好规划后再动手编写项目很重要。规划可确保你不偏离轨道,从而提高项目成功的可能性。
  • pip是一个负责为你下载并安装Python包的程序。接下来的几小节介绍如何使用pip来安装Python包。
  • 为访问Pygame检测到的事件,我们使用方法pygame.event.get()。所有键盘和鼠标事件都将促使for循环运行。
  • 在我们移动游戏元素时,pygame.display.flip()将不断更新屏幕,以显示元素的新位置,并在原来的位置隐藏元素,从而营造平滑移动的效果。
  • 在❷处,我们调用方法screen.fill(),用背景色填充屏幕;这个方法只接受一个实参:一种颜色。
  • 要将游戏元素居中,可设置相应rect对象的属性center、centerx或centery。要让游戏元素与屏幕边缘对齐,可使用属性top、bottom、left或right;要调整游戏元素的水平或垂直位置,可使用属性x和y,它们分别是相应矩形左上角的x和y坐标。
  • 在Pygame中,原点(0, 0)位于屏幕左上角,向右下方移动时,坐标值将增大。在1200×800的屏幕上,原点位于左上角,而右下角的坐标为(1200,800)。
  • 在❺处,我们定义了方法blitme(),它根据self.rect指定的位置将图像绘制到屏幕上。
  • 重构旨在简化既有代码的结构,使其更容易扩展。
  • 出于简化的目的,我们给导入的模块game_functions指定了别名gf。
  • 下面来改进控制方式,允许持续移动。
  • 这里之所以可以使用elif代码块,是因为每个事件都只与一个键相关联;如果玩家同时按下了左右箭头键,将检测到两个不同的事件。
  • rect的centerx等属性只能存储整数值
  • 通过使用精灵,可将游戏中相关的元素编组,进而同时操作编组中的所有元素。
  • 注意 代码super(Bullet, self).__init__()使用了Python 2.7语法。这种语法也适用于Python 3,但你也可以将这行代码简写为super().__init__()。
  • en_invasion.py中创建一个编组(group),用于存储所有有效的子弹,以便能够管理发射出去的所有子弹。这个编组将是pygame.sprit
  • 当你对编组调用update()时,编组将自动对其中的每个精灵调用update(),因此代码行bullets.update()将为编组bullets中的每颗子弹调用bullet.update()。
  • 因为将输出写入到终端而花费的时间比将图形绘制到游戏窗口花费的时间还多。

第13章 外星人

  • 对编组调用draw()时,Pygame自动绘制编组的每个元素,绘制位置由元素的属性rect决定。在这里,aliens.draw(screen)在屏幕上绘制编组中的每个外星人。
  • 我们将使用sprite.groupcollide()检测两个编组的成员之间的碰撞。
  • 新增的这行代码遍历编组bullets中的每颗子弹,再遍历编组aliens中的每个外星人。每当有子弹和外星人的rect重叠时,groupcollide()就在它返回的字典中添加一个键-值对。两个实参True告诉Pygame删除发生碰撞的子弹和外星人。(要模拟能够穿行到屏幕顶端的高能子弹——消灭它击中的每个外星人,可将第一个布尔实参设置为False,并让第二个布尔实参为True。这样被击中的外星人将消失,但所有的子弹都始终有效,直到抵达屏幕顶端后消失。)
  • 方法spritecollideany()接受两个实参:一个精灵和一个编组。它检查编组是否有成员与精灵发生了碰撞,并在找到与精灵发生了碰撞的成员后就停止遍历编组。在这里,它遍历编组aliens,并返回它找到的第一个与飞船发生了碰撞的外星人。

记分

  • 函数round()通常让小数精确到小数点后多少位,其中小数位数是由第二个实参指定的。然而,如果将第二个实参指定为负数,round()将圆整到最近的10、100、1000等整数倍。❶处的代码让Python将stats.score的值圆整到最近的10的整数倍,并将结果存储到rounded_score中。
  • 鉴于在任何情况下都不会重置最高得分,我们在__init__()中而不是reset_stats()中初始化high_score。

第15章 生成数据

  • 数据可视化指的是通过可视化表示来探索数据,它与数据挖掘紧密相关,而数据挖掘指的是使用代码来探索数据集的规律和关联。
  • 最流行的工具之一是matplotlib,它是一个数学绘图库,我们将使用它来制作简单的图表,如折线图和散点图。
  • 15.1 安装matplotlib
  • 要查看使用matplotlib可制作的各种图表,请访问http://matplotlib.org/的示例画廊。单击画廊中的图表,就可查看用于生成图表的代码。
  • 修改标签文字和线条粗细
  • 而函数tick_params()设置刻度的样式(见❹),其中指定的实参将影响x轴和y轴上的刻度(axis='both'),并将刻度标记的字号设置为14(labelsize=14)。
  • 当你向plot()提供一系列数字时,它假设第一个数据点对应的x坐标值为0,但我们的第一个点对应的x值为1。为改变这种默认行为,我们可以给plot()同时提供输入值和输出值:
  • 使用plot()时可指定各种实参,还可使用众多函数对图形进行定制。
  • 使用scatter()绘制散点图并设置其样式
  • 要绘制单个点,可使用函数scatter(),并向它传递一对x和y坐标,它将在指定位置绘制一个点:
  • 实参s设置了绘制图形时使用的点的尺寸
  • 要绘制一系列的点,可向scatter()传递两个分别包含x值和y值的列表
  • 函数axis()要求提供四个值:x和y坐标轴的最小值和最大值。
  • 要删除数据点的轮廓,可在调用scatter()时传递实参edgecolor='none':
  • 要让程序自动将图表保存到文件中,可将对plt.show()的调用替换为对plt.savefig()的调用:
  • 随机漫步是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的。
  • RandomWalk类只包含两个方法:__init__()和fill_walk(),其中后者计算随机漫步经过的所有点。
  • 为做出随机决策,我们将所有可能的选择都存储在一个列表中,并在每次做决策时都使用choice()来决定使用哪种选择(见❶)。
  • 为修改坐标轴,使用了函数plt.axes()(见❶)来将每条坐标轴的可见性都设置为False。
  • 函数figure()用于指定图表的宽度、高度、分辨率和背景色。
  • 方法roll()使用函数randint()来返回一个1和面数之间的随机数(见❷)。这个函数可能返回起始值1、终止值num_sides或这两个值之间的任何整数。
  • 我们使用add()将一系列值添加到图表中(向它传递要给添加的值指定的标签,还有一个列表,其中包含将出现在图表中的值)

第16章 下载数据

  • 要在文本文件中存储数据,最简单的方式是将数据作为一系列以逗号分隔的值(CSV)写入文件。这样的文件称为CSV文件。
  • CSV文件对人来说阅读起来比较麻烦,但程序可轻松地提取并处理其中的值,这有助于加快数据分析过程。
  • 模块csv包含函数next(),调用它并将阅读器对象传递给它时,它将返回文件中的下一行。在前面的代码中,我们只调用了next()一次,因此得到的是文件的第一行,其中包含文件头(见❸)
  • 我们对列表调用了enumerate()(见❶)来获取每个元素的索引及其值。
  • 我们创建了一个名为highs的空列表(见❶),再遍历文件中余下的各行(见❷)。阅读器对象从其停留的地方继续往下读取CSV文件,每次都自动返回当前所处位置的下一行。由于我们已经读取了文件头行,这个循环将从第二行开始——从这行开始包含的是实际数据。每次执行该循环时,我们都将索引1处(第2列)的数据附加到highs末尾(见❸)
  • 在❹处,我们调用了fig.autofmt_xdate()来绘制斜的日期标签,以免它们彼此重叠
  • 方法fill_between(),它接受一个x值系列和两个y值系列,并填充两个y值系列之间的空间
  • 实参alpha指定颜色的透明度。Alpha值为0表示完全透明,1(默认设置)表示完全不透明
  • 16.2 制作交易收盘价走势图:JSON格式
  • Python不能直接将包含小数点的字符串'6928.6492'转换为整数。为了消除这种错误,需要先将字符串转换为浮点数(float),再将浮点数转换为整数(int):
  • 这里首先用函数float()将字符串转换为小数(见❶),然后再用函数int()去掉小数部分(截尾取整),返回整数部分。
  • x_label_rotation=20让x轴上的日期标签顺时针旋转20°,show_minor_x_labels=False则告诉图形不用显示所有的x轴标签。
  • 为了验证周期性的假设,需要首先将非线性的趋势消除。对数变换(log transformation)是常用的处理方法之一。

第17章 使用API

  • Web API是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互。这种请求称为API调用。请求的数据将以易于处理的格式(如JSON或CSV)返回。依赖于外部数据源的大多数应用程序都依赖于API调用,如集成社交媒体网站的应用程序。
  • 这个API返回JSON格式的信息,因此我们使用方法json()将这些信息转换为一个Python字典
  • 很多API都要求你注册获得API密钥后才能执行API调用。编写本书时,GitHub没有这样的要求,但获得API密钥后,配额将高得多。
  • Pygal根据与键'value'相关联的数字来确定条形的高度,并使用与'label'相关联的字符串给条形创建工具提示。
  • 不确定某个键是否包含在字典中时,可使用方法dict.get(),它在指定的键存在时返回与之相关联的值,并在指定的键不存在时返回你指定的值(这里是0)

第18章 Django入门

  • Django是一个Web框架——一套用于帮助开发交互式网站的工具。Django能够响应网页请求,还能让你更轻松地读写数据库、管理用户等。
  • 如果你使用的是Windows系统,请使用命令ll_env\Scripts\activate(不包含source)来激活这个虚拟环境。
  • Django仅在虚拟环境处于活动状态时才可用
  • 千万别忘了这个句点,否则部署应用程序时将遭遇一些配置问题。如果忘记了这个句点,就将创建的文件和文件夹删除(ll_env除外),再重新运行这个命令。
  • SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,因为它让你不用太关注数据库管理的问题。
  • localhost是一种只处理当前系统发出的请求,而不允许其他任何人查看你正在开发的网页的服务器。
  • 我们将使用models.py来定义我们要在应用程序中管理的数据。
  • 命令makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型Topic创建一个表。
  • 每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。
  • 这些代码导入我们要注册的模型Topic(见❶),再使用admin.site.register()(见❷)让Django通过管理网站管理我们的模型。
  • 修改models.py,执行命令python manage.py makemigrationsapp_name,再执行命令python manage.py migrate。
  • 为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set
  • 每次修改模型后,你都需要重启shell,这样才能看到修改的效果。要退出shell会话,可按Ctr+D;如果你使用的是Windows系统,应按Ctr+Z,再按回车键。

第19章 用户账户

  • Django使用模板标签{% csrf_token %}(见❷)来防止攻击者利用表单来获得对服务器未经授权的访问(这种攻击被称为跨站请求伪造)
  • 装饰器(decorator)是放在函数定义前面的指令,Python在函数运行前,根据它来修改函数代码的行为。

附录A 安装Python

  • A.4.1 Python关键字

附录C 寻求帮助

  • · 你想要做什么? · 你已尝试哪些方式? · 结果如何?
  • Stack Overflow(http://stackoverflow.com/)是最受程序员欢迎的问答网站之一