Python物理建模初学者指南(第2版)

978-7-115-62809-1
作者: [美]杰西·M.金德(Jesse M. Kinder)[美]菲利普·纳尔逊(Philip Nelson)
译者: 吴进操
编辑: 郭泳泽
分类: Python

图书目录:

详情

本书介绍了如何使用 Python语言进行物理建模,包括完成二维和三维图形绘制、动态可视化、蒙特卡罗模拟、常微分方程求解、图像处理等常见任务。本书在第 1版的基础上增加了关于用 SymPy进行符号计算的新内容,介绍了用于数据科学和机器学习的 pandas和 sklearn库、关于 Python类和面向对象编程的入门知识、命令行工具,以及如何使用 Git进行版本控制。 本书适合对科学计算感兴趣、想要使用 Python完成物理建模的学生和研究人员阅读。

图书摘要

版权信息

书名:Python物理建模初学者指南:(第2版)

ISBN:978-7-115-62809-1

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


版  权

著    [美]杰西·M.金德(Jesse M. Kinder) 菲利普·纳尔逊(Philip Nelson)

著    吴进操

责任编辑 郭泳泽

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

版 权 声 明

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage and retrieval system, without permission in writing from the Publisher.

本书中文简体字版由Princeton University Press授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制本书内容。

版权所有,侵权必究。

内 容 提 要

本书介绍了如何使用Python语言进行物理建模,包括完成二维和三维图形绘制、动态可视化、蒙特卡罗模拟、常微分方程求解、图像处理等常见任务。本书在第1版的基础上增加了关于用SymPy进行符号计算的新内容,介绍了用于数据科学和机器学习的pandas和sklearn库、关于Python类和面向对象编程的入门知识、命令行工具,以及如何使用Git进行版本控制。

本书适合对科学计算感兴趣、想要使用Python完成物理建模的学生和研究人员阅读。

前  言

为什么要自学Python,为什么以这种方式自学

学习计算机编程会让你视野大开。刚开始接触编程时,你可能会感到困难重重,偶尔也能发现一些精妙绝伦的技巧,但掌握了基本的编程思维后,你就会发现计算机几乎可以做任何事情:可以模拟那些考虑了摩擦力和空气阻力的运动问题,可以构建捕食者和被捕食者模型来探索种群动态,可以生成分形图案,可以在股票市场中寻找隐藏的规律……这个清单不胜枚举。

为了与计算机交流,你必须掌握一种计算机能理解的语言。Python是一个理想的选择,因为它入门简单,而且与其他计算机语言相比,结构非常自然。你会发现,你更多地在思考如何解决问题,而不是如何让计算机明白你的思路。

无论你学习Python的目的是什么,你都可能想知道是否真的需要阅读本书的全部内容。请相信我们。我们是专业的科学家,已经根据多年经验为你制定了能够快速地开始自己的探索和学习的方案。按照我们建议的顺序,花几个小时尝试我们推荐的所有内容,从长远来看,会让你在未来省时省力。我们已经帮你筛选了不必要的内容。剩下的是必备的知识和技能,它们在未来将对你大有裨益。

如何使用本书

下面是如何利用本书自学Python的一些建议。

本书配套提供书中出现的许多代码示例。请充分利用这些资源。

阅读完前几页之后,你需要在工作的计算机上运行Python (别担心,我们会指导你如何设置)。在这台计算机上,你可以打开本书的配套资源中名为code_samples的库。

你可以在计算机旁放一本本书的纸质版,或者在平板计算机或其他设备上阅读电子版。你也可以在运行Python的计算机上打开本书的电子版。

本书有很多需要你大胆尝试的内容,包括正文中给出的代码片段。你可以从code_samples库中复制代码,并粘贴到Python会话中,观察结果,并尝试修改和运行。

部分章节和脚注标有代表“第二学习路径”的符号:。这些内容较为高阶,在第一次阅读时可以直接跳过。

现在让我们开始吧!

资源与支持

资源获取

本书提供如下资源:

配套代码示例;

本书思维导图;

异步社区7天VIP会员。

要获得以上资源,扫描下方二维码,根据指引领取。

提交错误信息

作者、译者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区(www.epubit.com),按书名搜索,进入本书页面,单击“发表勘误”,输入错误信息,单击“提交勘误”按钮即可(见下页图)。本书的作者、译者和编辑会对您提交的错误信息进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

与我们联系

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们。

如果您所在的学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接通过邮件发送给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

关于异步社区和异步图书

“异步社区”是由人民邮电出版社创办的IT专业图书社区,于2015年8月上线运营,致力于优质内容的出版和分享,为读者提供高品质的学习内容,为作译者提供专业的出版服务,实现作译者与读者在线交流互动,以及传统出版与数字出版的融合发展。

“异步图书”是异步社区策划出版的精品IT图书的品牌,依托于人民邮电出版社在计算机图书领域40余年的发展与积淀。异步图书面向IT行业以及各行业使用IT技术的用户。

第1章 Python入门

提花织机织出花叶图案,而分析引擎织出代数图案。

——阿达·洛芙莱斯

1.1 算法与算法思维

本书的目标是帮助你使用Python这门计算机语言来学习计算科学的基础知识。Python是一款开源软件,可以免费下载、安装和使用。关于Python的介绍有很多优秀的资料,而且数量还在不断增加。本书不仅教你如何使用Python,还重点讲解如何用它来解决物理建模中遇到的问题。这也是本书的独特之处。

物理系统建模可能是一项错综复杂的任务。如何借助计算机内部强大的处理器来助一臂之力?让我们一起来探索吧。

1.1.1 算法思维

假设你遇到了这样一个情况:你需要向一个从未开过车的朋友描述怎样把车从私家车道上倒出来。

你需要将上述任务分解成若干简单明了的步骤,便于你的朋友理解。例如,你可以向你的朋友提供以下一组指令:

1  插入钥匙。
2  转动钥匙,直到汽车发动,然后松手。
3  按下换挡杆上的按钮,并将其移至“倒挡”。
4  ……

遗憾的是,对于许多汽车来说,即使你的朋友理解每个指令,这个“代码”也无法工作,因为它有一个程序错误。在第3步之前,许多汽车要求驾驶员:

踩下左踏板。

另外,挡位的标记可能是“R”而不是“倒挡”。在编写这样的指令时,很难在一开始就达到较高的精度要求。

因为你的指令不是跟随操作进度而实时给出的,所以还需要考虑一些可能发生的意外情况:

如果听到嘎吱声,踩下左踏板……

将较长的操作步骤分解为小的且明确的子步骤并预先考虑意外情况是算法思维的开始。

如果你的朋友有很多看别人开车的经验,那么上面的指令可能就足够他理解操作步骤了。但如果面对的是机器人,则需要更多的细节。例如,前两个步骤可能需要扩展为以下内容:

抓住钥匙的宽端。
将钥匙的尖端插入方向盘柱右下侧的槽中。
沿顺时针方向(当从宽端向尖端看时)围绕其长轴旋转钥匙。
……

这两组指令说明了跟计算机沟通时低级语言和高级语言的差异。低级计算机程序类似于第二组明确指令,用机器能够理解的语言编写[1]高级系统可以理解许多常见任务,因此可以以较为简洁的方式编程,类似于上面的第一组指令。Python是一种高级语言,它提供了许多常用的命令,例如数学计算、文本处理和文件处理。另外,Python还可以调用许多标准库,这些标准库包含一系列程序,可以执行数据可视化和图像处理等高级功能。

[1] 机器代码和汇编语言是低级编程语言。

Python还附带了一个命令行解释器——在此程序中,输入Python命令后即可执行这些命令。因此,在Python中,既可以将指令保存在文件中以便未来运行,又可以输入命令立即执行。相比之下,科学计算中使用的许多其他编程语言,如C++或Fortran,则会要求在执行程序之前先编译程序。一个叫作编译器的独立程序会将你的代码翻译成低级语言。然后,运行生成的编译程序来执行(实现)算法。而使用Python,快速编写、运行和调试程序都相对容易(不过,这仍然需要耐心和练习)。

命令行解释器结合标准库和你自己编写的程序,构成了一个既方便又强大的科学计算平台。

1.1.2 状态

在很久以前的几何课上,你可能学过多步数学证明,即使用给定信息和形式系统,通过一系列步骤,最终验证命题。因此,一个命题的真假,虽然孤立地看并非显而易见,但是根据之前的一系列命题,应该是直截了当的。读者的“状态”(当前真命题列表)在通读证明的过程中会不断变化。最后,状态列表会加上预期的结果。

算法具有不同的目标。算法是一系列指令,每个指令描述一个简单的操作,最终完成一项复杂的任务。这些指令可能涉及大量重复,因此你不会希望监督每个步骤的执行。相反,你可以提前指定所有步骤,然后让电子助手快速执行这些步骤,自己则退居一旁。当然,也可能存在无法预知的意外情况(例如前面提到的“听到嘎吱声”)。

在算法中,计算机的状态不断被修改。计算机有许多存储单元,其内容可能在操作过程中发生变化。你的目标可能是在算法运行完成后,安排其中一个或多个存储单元保存某些复杂计算的结果。你可能还希望显示特定的图形图像。

1.1.3 a=a+1的意思

要让计算机执行算法,必须先用编程语言表达出来。在开始阶段,计算机编程中使用的命令可能会令人困惑,尤其是当这些命令与标准的数学用法相矛盾时。例如,许多编程语言(包括Python)都接受以下语句:

1  a = 100
2  a = a + 1

在数学上,这毫无道理。第2行是一个永远错误的断言。等价地说,它是一个没有解的方程。然而,对于Python,“=”不是相等性判断,而是要执行的指令。这些语句大致有以下含义[2]

[2] 附录F给出了Python内部关于赋值语句处理的精确信息。

(1)将整数对象(值为100)赋给名称a (即变量)。

(2)取出对象a的值。计算该值与1的和。将结果赋值给名称a,并丢弃以前存储在名称a下的内容。

换句话说,上述等号的作用是指示Python更改其状态。而在数学符号中,等号的作用是判断命题真假,命题可能为真,也可能为假。另外,还要注意,Python对命令x=y的左右两侧有不同的处理,而在数学中,等号是对称的。例如,如果你输入b+1=a, Python将给出一条错误消息。赋值语句的左侧必须是一个名称,否则右侧求值的结果无法赋值给左侧。

我们经常需要检查变量是否等于某个特定值。为了避免赋值和等号二者之间的歧义,Python使用双等号表示相等关系:

1  a = 1
2  a == 0
3  b = (a == 1)

这段代码再次创建变量a,并将一个数值赋给它。然后将该数值与0比较。最后,创建第二个变量b,并在执行另一次比较后为其赋予一个逻辑值(TrueFalse)。该值可以在或然代码中使用,我们将在后面看到。

当需要== (相等性判断)时,不要使用= (赋值操作)。

对于编程的初学者来说,这是一个常见的错误。如果发生此错误,你可能会得到不可思议的结果,因为===都是合法的Python语法。然而,具体到任何特定的情况,只有一个结果是你想要的。

1.1.4 符号与数字

在数学中,即使读者还不知道a的值,也可以“设b=a2-a”,然后开始推导。在该语句中,不管a的值是什么,都可以用a来定义b

但如果你启动Python并立即输入等价的语句b=a**2-a,结果将是一条错误消息[3]。每次按下<Return>,Python都会尝试计算每个赋值语句的值。如果变量a还没有被赋值,则计算失败,Python会报错。虽然其他计算机数学包可以接受这样的输入,跟踪符号关系,并在以后对其进行计算,但原生Python是不能的[4]

[3] 符号**表示幂运算。见1.4.2节。

[4] SymPy库使Python中的符号计算成为可能。见10.3.2节。

“设b=a2-a”这样的定义将在整个讨论过程中保持不变,这是理所当然的。如果我们说,“在a=1的情况下……”,那么读者知道b等于零;如果我们稍后说,“在a=2的情况下……”,那么我们就不必重申b的定义,读者也会知道这个符号现在代表值22-2=2。

相反,像Python这样的数值系统在执行赋值b=a**2-a之后会忘记ba之间的任何关系。它只记得现在赋给b。如果后面改变a的值,b的值不会发生改变[5]

[5] 在数学中,语句b=a2-a本质上将b定义为a的函数。Python当然也可以实现这一点,方法是定义一个返回值为a2-a的函数并将该函数赋给名称b(见6.1节),但“=”的作用并非如此。

在数学证明过程中改变符号关系通常是不可取的。然而,在Python中,如果开始宣称b=a**2-a,那么没有什么能阻止后面把它改成b=2**a。第二个赋值语句丢弃了第一个赋值语句中计算的值,并用新计算的值替换它,从而更新了Python的状态。

1.2 启动Python

不要只是阅读输入某个命令时会发生什么,而是要亲自尝试这些命令。附录A描述了如何安装和启动Python。从现在开始,你应该让Python处于运行状态,在阅读的同时,尝试每一段代码并观察Python的响应。例如,本书不会向你展示太多的图形或输出。你必须在阅读示例时自己生成这些图形或输出。

阅读本书并不能让你学会Python。你需要学习这里的所有示例和练习,然后将所学知识用于解决自己的问题,才能学会Python。

请给自己设定一些小挑战(如果……会发生什么?我怎样才能完成……?),然后不断测试。Python不是昂贵的实验室设备,不会因为输入错误的内容而损坏或爆炸!请大胆尝试。这种策略不但比被动积累事实更有趣,而且效果也要好得多。

在你开始输入代码之前,我们需要先解释一下本书中使用的一些约定。其中最重要的约定如下:

Python代码完全由纯文本组成。

本书代码示例中的所有字体、字型等都是为了便于阅读而添加的。在输入代码时,你不需要担心这些事情。类似地,代码示例左侧显示的行号可以方便我们快速找到特定的行。不要输入行号。当你在编辑器中工作时,Spyder将分配并显示行号,Python将使用行号来告诉你哪里出现了错误。行号不是代码的一部分。另外,还要注意,大多数空格是可有可无的,但用于缩进的空格是不可或缺的。我们使用额外的空格来提高可读性,但这些并不是必需的。

本书在显示代码时使用以下字体方案:

注释以斜体显示#这是一条注释。

函数参数中的键值以斜体显示:np.loadtxt('data.csv', delimiter=',')。键值不能随意指定,键值必须正确拼写。

可以用鼠标单击的按钮以小型大写字母显示在矩形中:。Spyder中有些按钮是图标,不是文本,但将鼠标指针悬停在按钮上时将显示本书中所示的文本。

按键显示在尖括号内:<Return><Ctrl-C>

其他大多数文本不以特殊格式显示。

我们的按键符号可能与你的键盘不完全相同,因此我们对相关的约定进行了汇总,如表1.1所示。尖括号中出现的所有键应同时按下。例如,<Ctrl-C>表示按住键盘上的“control”键,并同时按住“C”键。我们的约定遵循macOS键盘布局。如果你使用的是Windows或Linux,请用<Ctrl>替代<Cmd>。另外,我们将“return或enter”简写<Return>

表1.1 按键符号

按键

使用示例

示例对应的功能

enter或return

<Return>

结束行或运行命令

control

<Ctrl-C>

中断当前Python命令

command

<Cmd-V>

从剪贴板粘贴

option或alt

<Alt-Shift-R>

重新启动Spyder

你已经知道了要输入什么(纯文本)以及如何输入,现在万事俱备,只差Python!完整的Python编程环境有许多组件。表1.2简要说明了我们将要用到的组件。请注意,在本指南中,“Python”一词的使用比较自由。Python除了指语言本身,还可以指Python解释器(一种计算机应用程序,可以接受命令并执行程序中描述的步骤)。另外,Python还可以同时指Python语言和公共库。

表1.2 本书中Python环境的组成

名称

描述

Python

一种计算机编程语言。一种向计算机描述算法的方法

IPython

一种Python解释器:一种计算机应用程序,为执行Python命令和程序提供了方便的交互模式

Spyder

一种集成开发环境:一种计算机应用程序,包括IPython、一个检查变量的工具和一个用于编写与调试程序的文本编辑器等

Jupyter

一种用于Python的笔记本式界面

NumPy

一个标准库,提供数值数组和数学函数

PyPlot

一个标准库,提供可视化工具

SciPy

一个标准库,提供科学计算工具

Anaconda

一种发行版:可一次下载上述所有组件,并提供许多其他特殊用途的库的访问。它还包括一个包管理器,帮助你更新所有组件

本书中的大部分代码可以在任何Python发行版中运行。然而,因为无法为每个可用的Python版本和每个集成开发环境(Integrated Development Environment, IDE)提供说明,所以我们选择了以下特定设置。

Python 3的Anaconda发行版,可在其官方网站获得。许多科学家仍然使用早期版本的Python(如2.7版)。附录E讨论了如何将本书中的代码进行微小更改,以适应早期版本。

Spyder IDE是Anaconda附带的,也可以在其官方网站获得。任何编程任务都可以使用不同的IDE来完成,或者根本不使用IDE来完成。其他IDE也是可用的,例如IDLE,它附带了Python的各个发行版。另外,还可以选择基于浏览器的Jupyter Notebook和JupyterLab。

发行版的选择取决于个人偏好。我们选择Anaconda是因为它安装、更新和维护都很简单,而且免费。你可能会发现,其他的发行版更适合你的需求。例如,你可以从Python网站安装Python并使用pip管理包,但本书假设你使用的是Anaconda和conda包管理器。

1.2.1 IPython控制台

为了让我们的讨论集中在Python,而不是各种平台的细节上,我们假设你在阅读本指南时使用的是Spyder。但这不是必需的!如果你希望从更简单的界面开始,可以在Anaconda Navigator中打开Qt控制台应用程序,并开始输入命令。如果你喜欢笔记本界面,可以使用Jupyter Notebook(参见附录C)。如果你喜欢在命令行中工作,可以从终端启动IPython(见附录B)。不过,在某些情况下,你需要一个IPython解释器和一个文本编辑器。Spyder包含了这两个功能,以及其他一些有用的功能,其界面也是MATLAB用户所熟悉的。使用Python有许多种方法,你可以在学习本书时使用其中任何一种方法。如果你是Python新手,Spyder是一个不错的选择。

现在打开Spyder。启动后,Spyder会打开一个窗口,其中包含多个窗格,见图1.1。左边是编辑器窗格,用于编辑程序文件(脚本)。右边有两个窗格。

图1.1 Spyder界面。添加圆圈是为了强调(从上到下、从左到右)按钮、首选项(扳手图标)、变量管理器中的变量、将变量管理器置于其窗格前部的选项卡、按钮、IPython命令提示符和IPython控制台选项卡

右上角窗格可能包含帮助、变量管理器、绘图和文件管理器选项卡。如果有必要,单击变量管理器的选项卡,可将其置于最前面。右下角窗格应包括IPython控制台的选项卡;如果需要,可以单击它[6]。这里提供了命令行解释器,你可以在输入Python命令时以交互方式执行命令。

[6] 如果没有出现IPython控制台选项卡,可以从界面顶部的菜单中打开:“Consoles”>“New console”。

如果你的窗口布局变得杂乱无章,不要担心。窗口布局很容易调整。Spyder的标准格式是一个窗口,分为刚才描述的3个窗格。每个窗格可以有多个选项卡。如果有不需要的窗口,可以单击按钮分别关闭它们。你还可以使用菜单“View”>“Panes”选择要显示的窗格,并停用不需要的窗格。点击“View”>“Window layouts”>“Spyder Default Layout”,将恢复标准布局。

单击IPython控制台内部。现在,你输入的内容将显示在命令提示符后。默认情况下,命令提示符类似于:

In[1]:

尝试输入简单的命令,如“2+2”,并在每行后按<Return>。Python在每次<Return>后立即响应,以尝试执行你输入的任何命令[7]

[7] 本书使用“命令”一词来表示可由解释器执行的任何Python语句。像a=1这样的赋值,像plt.plot(x,y)这样的函数调用,以及像%reset这样的特殊指令都是命令。

单击变量管理器选项卡。每次输入命令并按<Return>后,此窗格的内容将反映Python状态的任何变化:最初为空,然后显示变量列表及其值的摘要[8]。当变量包含多个值(例如数组)时,双击列表中的该变量,可以打开包含该数组所有值的电子表格。你可以在此电子表格中复制数据并粘贴到其他应用程序中。

[8] 某些变量不会显示。你可以通过变量管理器窗格右上角的菜单来控制哪些变量被排除在外。

在任何时候,你都可以通过退出并重新启动Python,或者通过执行以下命令来重置Python的状态:

%reset

由于此操作将删除会话中创建的几乎所有内容,是不可逆的,因此它需要你确认[9]。按<Y>,然后按<Return>继续。(以%符号开头的命令是魔法命令,即IPython解释器中特有的命令。魔法命令可能不适用于原生Python解释器和你编写的脚本。要了解更多信息,请在IPython命令提示符下输入%magic。)

[9] 如果IPython似乎没有对%reset响应,请尝试手动向上滚动IPython控制台以查看确认询问。

示例:使用%reset命令,然后在提示符下尝试以下命令。如下所示准确输入每一行,然后按<Return>,解释你所看到的结果:

q
q == 2
q = 2
q
q == 2
q == 3

解答:对于前两行,Python会报错。最初,符号q没有与任何对象关联,它没有值,因此涉及q的表达式是无法计算的。第3行改变了Python的状态,进而会改变这种情况,因此最后3行不会产生错误。

示例:现在再次清除Python的状态。在提示符下尝试以下操作,并解释你所看到的结果(参考1.1.4小节可能会有用):

a = 1
a
b = a**2 - a
b
a = 2
print(a)
print(b)
b = a**2 - a
a, b
print(a, b)

解答:前4行的结果应该很清楚——我们给变量ab赋值。在第5行中,我们更改了a的值,但因为Python只记住b,而记不住它与a的关系,所以b的值是不变的,直到我们在第8行显式地更新b的值。

在命令提示符下输入代码时,你可能会遇到一种令人困惑的情况,Python似乎没有响应,只显示“...:”,而不是执行命令。

如果命令包含不成对的(、[或{,则Python将继续读取更多行,搜索相应的)、]或}。

现在请寻找不匹配的括号。如果找到,请输入右括号并按<Return>。如果不知道如何匹配括号,或者有其他问题,可以使用<Shift-Return>强制执行,或者按<Esc>中止命令[10]

[10] <Esc>会取消Spyder中的当前命令。在其他IDE或解释器中,可能需要使用<Ctrl-C>进行中断,使用<Alt-Return>进行强制执行。

上面示例说明了一个要点:赋值语句不会显示赋值之后变量的值。要在IPython会话中查看赋值之后变量的值,可以使用print()命令或在单独的一行中输入变量名[11]

[11] 在你编写的脚本中,Python将计算表达式,但不会在屏幕上显示任何内容;如果想要输出结果,就必须给出一个显式的print()命令。脚本将在3.3节中讨论。

上面示例的最后两行展示了如何一次查看多个对象的值。请注意,两行的输出并不完全相同。

你可以通过开始新行来结束命令,也可以用分号(;)结束命令然后在同一行上添加另一个命令。

你还可以使用单个=命令进行多个赋值。这是使用分号的替代方法。以下两行都是将相同的值赋给各自的变量:

a = 1; b = 2; c = 3
x, y, z = 1, 2, 3

第二个命令的任何一侧都可以用括号括起来,结果不会受到影响。

前面的段落展示了用Python节省空间和简化输入的方法。有时候这很方便,但最好不要过多地使用这种能力。相反,你应该尝试使代码的含义尽可能清晰。为了便于阅读,值得在程序中花费一点额外的时间或者多输入几行代码。

在某些情况下,你可能希望使用一个很长的命令,但一行又容纳不下。在这种情况下,可以用反斜杠(\)结束一行。这时,Python将继续读取下一行作为同一命令的一部分。尝试以下命令:

q = 1 + \
2
print(q)

一个命令甚至可以扩展到多行:

xv\
a\
l\
= 1 + \
2

这将创建变量xval并将其赋值为3。

若要编写清晰的代码,可以使用少量的反斜杠和分号。

1.2.2 错误消息

到目前为止,你应该已经遇到了一些错误消息。当Python检测到错误时,它会告诉你在哪里遇到了错误,提供引起问题的语句周围的代码片段,并告诉你在它识别的许多类型中检测到了哪种类型的错误。例如,每当尝试计算未定义的变量时,Python都会以NameError进行响应(回想1.2.1小节的示例)。附录D描述了Python的常见错误以及解释错误消息的一些提示。

著名的计算机科学家高德纳(Donald Knuth)曾写道:“当你没有做好准备时,错误消息可能是可怕的;但当你有正确的态度时,错误消息就会很有趣。只要记住,你真的没有伤害计算机的感情,没有人会因为这些错误而责备你。”我们鼓励你采取这种态度。

不要害怕犯错误。计算机很难弄坏。

阅读错误消息。它们会告诉你犯了什么样的错误,而不仅仅是你犯了错误。

检查产生错误的代码。你可以在错误中吸取教训。

这种处理错误的方法将使你成为一名更好的程序员,并将帮助你今后“调试”更复杂的程序[12]

[12] 见3.3.3小节。

1.2.3 帮助资源

关于Python的权威文档可在Python网站在线获得。然而,在许多情况下,你可以通过其他方式更快地找到所需的答案,例如询问朋友、搜索网页或访问Stack Overflow网站。

假设你想计算2的平方根。输入2**0.5并按<Return>。这可以完成任务,但Python会显示小数点后16位数字,而你只需要3位。你认为Python中可能有一个名为round的圆整函数,但你不确定如何使用它或它是如何工作的。在命令提示符下输入help(round),可以直接获得Python的帮助。你会看到这确实是你正在寻找的函数:

round(2**0.5, 3)

上述语句给出了期望的结果。

在Spyder中,获取帮助还有其他方法。在命令提示符下输入round,但不要按<Return>,而是按下<Cmd-I><Ctrl-I>I表示information一词)。原本使用help命令在IPython控制台中显示的信息,现在显示在了“帮助”选项卡中,并且格式更易于导航和阅读,特别是对于较长的信息。你也可以使用“帮助”选项卡,而不在命令提示符处输入任何内容:尝试在窗格顶部的“对象”字段中输入pow。“帮助”选项卡提供了**(求数的幂)的替代方法的信息。

在IPython中,你还可以在任何Python对象(包括函数和变量名)的名称后面或前面加一个问号以获得帮助:round??round提供的信息与help(round)几乎相同,但输入起来更容易。

当你输入help(...)时,如果Python识别出括号中的名称,它将打印出表达式的有关信息。遗憾的是,如果你不知道所需命令的名称,Python就不那么友好了。也许你认为应该有一种不使用幂求一个数的平方根的方法。毕竟,这是一个相当基本的操作。输入help(sqrt),看看当Python无法识别你请求的名称时会发生什么。

要了解当前可用的命令,可以使用Python的dir()命令。dir是directory一词的缩写,它会返回当前会话期间(或上次使用%reset命令以来)创建或导入的所有模块、函数和变量名的列表。可以使用Python的help(dir)了解更多的帮助信息。dir()的输出中貌似没有平方根方面的内容,但有一项是__builtins__。这是Python第一次启动时识别的所有函数和其他对象的集合。这是Python寻找函数或变量的“撒手锏”[13]。若要查看内置函数的列表,请输入:

[13] 附录F解释了Python如何搜索变量和其他对象。

dir(__builtins__)

然而并没有显示sqrt或类似的函数。事实上,sincosexp等标准的数学函数都没有出现!

此时此刻,Python也无法给你提供进一步的帮助。现在,你必须求助于外部资源。比较好的选择有Python书籍、搜索引擎、熟悉Python的朋友等。

在开始阶段,为了编码,你的大部分时间都将花在使用搜索引擎上。

我们要找的sqrt函数属于一个库。稍后,我们将讨论如何访问Python没有自动提供的实用函数库。

习题1A

在继续学习之前,请尝试在网上搜索“如何在Python中求平方根”。

1.2.4 最佳实践:记录日志

在学习本书时,你会遇到许多小困难,以及若干大困难,例如如何计算修正贝塞尔函数的值,怎样才能在图形轴标签中添加下标……难题是无穷无尽的。每次你解决这样一个难题(或朋友帮助你解决),都要在笔记本或计算机的某个专用文件中记下你是如何解决问题的。几个月之后,翻阅日志会比逐行查看之前编写的全部代码要容易得多(也比一遍又一遍地询问朋友更容易)。

1.3 Python模块

我们发现,Python没有内置的sqrt函数。可是,你的计算器却有!那么,Python有什么用?不妨停下来想一想:你的计算器究竟是如何知道怎样求平方根的。在过去的某个时候,有人想出了一种计算数的平方根的算法,并将其存储在计算器的永久内存中。若要计算平方根,必须有人创建一个程序

Python是一种编程语言。Python解释器可以理解一组基本的命令,基本命令组合起来可以执行复杂的任务。另外,Python还有一个庞大的开发人员社区,他们创建了完整的实用函数库。然而,要访问这些函数库,你需要将它们导入你的工作环境。

使用import访问标准Python没有自带的函数。

1.3.1 import

在命令提示符下,输入:

import numpy

然后按<Return>。现在,你可以访问许多实用函数。你已经导入了NumPy模块——使用Python进行数值计算的工具集合。NumPy代表Numerical Python。但在代码中,不要将其名称大写。

输入dir(numpy)查看所获所得。你会发现近600个可供使用的新选项,其中之一就是最初寻找的sqrt函数。在NumPy中,可以使用命令numpy.lookfor('sqrt')搜索函数(返回的结果通常会多于你的需求,但前面几行往往非常有用)。现在你已经导入了NumPy,请尝试:

sqrt(2)

怎么回事?刚才明明已经导入了平方根函数,但Python却告诉你sqrt没有定义!请改为以下语句,重新尝试:

numpy.sqrt(2)

你所需要的sqrt函数属于numpy模块。即使导入了模块,你仍然需要先告诉Python目标函数所在的模块,然后才能使用函数。

导入模块后,调用函数的方法是:依次写出模块名称、点号和目标函数的名称。

1.3.2 from ... import

导入函数还有另一种方法。例如,你可能希望访问NumPy中的所有函数,但又不想在函数前面输入“numpy.”前缀。不妨尝试以下命令:

from numpy import *
sqrt(2)

这很方便,但如果你想同时使用两个不同的模块,这可能会导致麻烦。有一个名为math的模块,它也有一个sqrt函数。如果同时从mathnumpy导入所有函数,那么在输入sqrt(2)时会调用哪个模块的函数?这在处理数字数组时很重要。为了保持直观,最好不要使用“from 模块名import *”命令,而是导入模块,并根据需要显式调用numpy.sqrtmath.sqrt。不过,这里还有一个折中的方案:你可以给模块取别名。尝试以下命令:

import numpy as np
np.sqrt(2)

如此一来,当不同的模块具有相同名称的函数时,我们既可以节省输入,又可以避免混淆。

在某些情况下,你可能只需要一个特定的函数,而不需要整个函数库。你可以通过函数名称导入特定的函数:

from numpy import sqrt, exp
sqrt(2)
exp(3)

我们只导入了NumPy模块中的两个函数,无须使用“numpy.”前缀即可访问这些函数。请注意,这里的导入命令和“from numpy import *”命令很相似。星号是一个“通配符”,它告诉导入命令需要获取所有内容。

稍微改变一下导入语句,你就可以为导入的函数提供自定义别名:

from numpy.random import random as rand
rand()

现在,我们有了一个随机数生成器,它有一个很方便输入的别名:rand

该示例还展示了模块中还有模块的现象:numpy模块包含numpy.random模块,而numpy.random模块又包含numpy.random.random函数。当我们输入import numpy时,我们导入了许多这样的子模块。当然,我们也可以只导入一个函数,方法是使用from,并提供目标函数的准确名称、目标函数所在的模块,以及目标函数的别名。

1.3.3 NumPy和PyPlot

NumPy和PyPlot是我们最常用的两个模块。NumPy提供了生成和分析数据所需的数值工具,PyPlot提供了可视化数据所需的工具。PyPlot是大型Matplotlib库的子集。从现在起,假设你已经发出以下命令:

import numpy as np
import matplotlib.pyplot as plt

这也可以通过单个命令完成:

import numpy as np, matplotlib.pyplot as plt

你应该在每次会话开始时执行这些命令,还应该在编写的任何脚本的开头添加这些行。每次使用%reset命令后,你也需要重新导入这两个模块。

输入%reset命令,然后尝试导入这些模块。探索NumPy和PyPlot提供的函数。你可以使用help()或1.2.3小节中描述的任何方法获得相关函数的信息。你一定会发现,NumPy帮助文件提供的信息量要远远大于内置Python函数帮助文件所提供的信息量。NumPy帮助文件通常包括可以在命令提示符下尝试的示例。

现在我们有了这些工具集,下面来看看可以用它们做什么。

1.4 Python表达式

Python语言有自己的语法。所谓语法是指一组用于构造表达式和语句的规则。在本节中,我们将研究一些简单的表达式,来领略一下如何与Python打交道。表达式的基本构成是字面量、变量名、运算符和函数。

1.4.1 数字

你可以通过多种方式输入显式数值(数值型字面量):

1231.23表示普通数字。但是,当输入一个大数字时,不要用逗号分隔数字(如果要输入一百万,不要输入1,000,000)。

2.3e5是2.3×105的简写。

2+3j表示复数2+3(这里用名称j代表虚数单位,工程师对此比较熟悉;数学家和物理学家需要适应Python的约定)。

Python内部会以不同的格式存储数字。但是Python一般只会在必要时转换数字类型。初学者通常不需要考虑这个问题。注意,在某些情况下,Python会要求使用整数。例如,a=1.0即使小数部分为零,Python也不会将其解释为整数。如果需要强制某个值为整数(例如,在表示列表中元素的索引时),可以使用intround函数。

1.4.2 算术运算和预定义函数

Python包含基本的算术运算符,例如+-*(乘)、/(除)和**(幂运算)。

Python使用双星号**表示求一个数的幂。

例如,a**2表示“a的平方”(符号a^2在其他一些数学软件中表示平方,但在Python中具有完全不同的含义)。

与标准数学符号不同,Python中的乘法必须包含乘法符号。尝试输入以下命令:

(2)(3)
a = 2; a(3)
3a
3 a

每个命令都会产生一条错误消息。但是,它们都不会生成这样的消息:“你忘了一个'*'!”根据Python使用的求值规则,这些表达式没有意义。Python不知道你试图表达什么,所以它无法确切地告诉你出了什么问题。不妨研究这些错误消息;你可能会再次遇到它们。附录D描述了这些错误消息和其他常见的错误。

算术运算的优先级(排序)与常识相符。

使用圆括号可以改变运算符的优先级。

与数学教科书不同,在Python中,只能使用圆括号改变优先级排序。方括号和花括号则用于其他目的。前面已经看到,圆括号还有另一种含义:将函数的参数括起来。此外,圆括号还有第三种含义:指定元组。Python根据上下文来确定要使用哪种含义。

例如,如果要使用数字,你可能会输入1/2*np.pi(原生Python不知道π的值,但NumPy知道)。试试看。

问题出在哪里?为什么?插入括号可以修复表达式的问题。稍后我们会遇到其他类型的运算符,如比较和逻辑运算符,它们也有一定的优先级排序。你可能并不想记住所有运算符的优先级,不过,你可以自由地使用括号来准确地表达你的意图。

为了熟悉Python的算术运算,试回答下面两个语句解决了什么样的著名数学问题,并检查Python能否正确处理:

a, b, c = 1, -1, -2
(-b + np.sqrt(b**2 - 4*a*c))/(2*a)

前面曾介绍过,np.sqrt是一个函数的名称,Python在启动时是无法识别它的,但一旦导入NumPy模块后,它就变得可用了。当Python遇到第二行中的表达式时,它会执行以下操作。

(1)通过用数值替换变量并执行算术运算来计算np.sqrt函数的参数的值,参数是指函数名后圆括号内的所有内容(参数本身可能包含函数)。

(2)中断表达式的计算,并执行一段名np.sqrt的代码,将步骤(1)中找到的结果传递给该代码。

(3)用np.sqrt返回的值替换表达式。

(4)按照正常程序完成表达式的求值。

如何知道哪些函数可用?参见1.2.3小节:在IPython控制台提示符下输入dir(np)dir(__builtins__)

Python和NumPy预先定义了若干符号。这些符号不需要任何参数或括号。试试np.pi(常数π)、np.e(自然对数的底数)和1j(虚数单位)。另外,NumPy还提供标准的三角函数,但在使用时要注意:

np.sinnp.cosnp.tan等三角函数中,参数的角度都采用弧度。

1.4.3 最佳实践:变量名

注意,如果你在无意之中修改了某个符号的值,Python并不能提供保护。例如,如果你发出了np.pi=22/7的命令,那么除非更改它或重置Python,否则np.pi的值就是22/7。你甚至可以用内置函数的名称创建变量,例如,round=3[14]。这再次说明,要使用“import numpy as np”命令,不要使用“from numpy import *”命令。你不太可能使用“np.”前缀将自己的变量命名为np.pinp.e。无论你如何定义pienp.pinp.e都将保留它们的标准值。

[14] 撤销此操作的方法是删除自己的round版本:输入del(round)。Python将恢复到其内置定义。

当代码变长后,你可能会在无意中多次使用同一个变量名。例如,你可能在开始时为某个变量分配一个通用的名称,如x,并在后面为了完全不同的目的而再次使用原来的名称。再后来,你可能需要原来的x,忘记了新的x。而此时,Python已经将原来的值覆盖,令人费解的现象也会随之出现。这就是名称冲突

变量最好使用有意义的名称。虽然输入所需的时间更长,但这有助于避免名称冲突,同时也使代码更易于阅读。也许你可以把第一个变量x改为index,因为它表示列表索引。也许你可以把第二个变量x改为total,因为它更符合逻辑。当你在后面调用index时,就不会出现名称冲突的问题了。

但是,请记住,这里的“有意义”是指“对人类读者有意义”。Python本身并不关注变量名的含义,例如,将变量命名为filename并不会告诉Python如何使用该变量。

变量名区分大小写,大多数预定义名称都是小写的。因此,在自己定义的变量名或函数名中包含大写字母,可以避免一定的名称冲突。

变量名中不允许使用空格和句点。有些程序员在变量名中使用大写(“驼峰命名法”)来表示单词边界,例如whichItem。有些程序员则使用下画线(“蛇形命名法”),如which_item。变量名也可以包含数字(myCount2),但必须以字母开头[15]

[15] 严格来说,名称也可以以下画线字符开头,但通常这样的名称是为Python内部使用保留的。

某些变量名是禁止使用的。Python不允许你将变量命名为ifforlambda保留字。你可以在网上搜索“Python保留字”找到它们。

1.4.4 再谈函数

你可能习惯于将一个函数(例如平方根函数)视为一台机器,以一个数字作为输入(其参数),并返回另一个数字(其结果)作为输出。部分Python函数确实具有这种特性,但是在Python中,函数的概念要广泛得多。下面仅做部分说明(有些函数我们目前还没有接触到)。

一个函数可以接受一个参数、多个用逗号分隔的参数,也可以不接受任何参数。

一个函数可以允许不同数量的参数,并且根据所提供参数数量的不同,其行为也会有所不同。例如,在后文的某些函数中,你可以使用键值参数来指定选项。每个函数的帮助文本通常会介绍参数的使用方式。

一个函数也可以返回多个值。返回值的数量甚至可以根据所提供的参数而变化。你可以使用一种特殊的赋值语句捕获返回值[16]

[16] 6.1.4小节将详细讨论函数的返回值。更准确地说,Python函数总是返回单个对象。但是,该对象可以是包含多个元素的元组。

一个函数除了返回结果,还可以通过其他方式更改计算机的状态。例如,plt.savefig将绘图保存到计算机硬盘上的文件中。其他可能的副作用包括将文本写入IPython控制台:print('hello')

如果使用不带圆括号的函数名,则是在引用该函数,而不是对其求值。在数学中,f是一个函数;f (2)是参数为2时函数的值。在IPython命令行输入np.sqrt,不带圆括号,查看Python是如何处理函数名的。

计算函数时,即使没有参数,也要始终包含括号。

如果一个函数接受两个或多个参数,那么它如何区分不同的参数?在数学表示法中,参数的顺序已经传达了这一信息。例如,如果我们定义f(x,y)=xe-y,那么f(2,6)表示2e-6:第一个给定值(2)用于替换定义中的第一个命名变量(x),以此类推。这种位置参数方案也是Python使用的标准方案。但是当一个函数接受许多参数时,严格依赖顺序可能会令人讨厌,而且容易出错。出于这个原因,Python还有一种替代方法,称为键值参数。例如:

f(y=6, x=2)

此语句的作用是用值6初始化名为y的变量,用值2初始化另一个名为x的变量,然后指示Python执行名为f的函数。在给定键值参数时,无须遵循任何特定顺序(但是,键值参数必须跟在所有位置参数后面,并且必须使用正确的名称,你可以在函数的文档中找到正确的参数名称)。许多函数都允许你忽略为其部分或全部键值参数指定值;如果省略它们,函数将提供默认值。6.1.3小节将进一步讨论键值参数。

现在,你已所知甚多,可以使用Python进行简单的计算了。试试本章中的例子,然后自己试验。在第2章中,我们将探讨如何使用Python编写简单的程序。

相关图书

AI辅助编程Python实战基于GitHub Copilot和ChatGPT
AI辅助编程Python实战基于GitHub Copilot和ChatGPT
Python极客项目编程(第2版)
Python极客项目编程(第2版)
动手学自然语言处理
动手学自然语言处理
Python网络运维自动化
Python网络运维自动化
Python财务应用编程
Python财务应用编程
Python机器学习之金融风险管理
Python机器学习之金融风险管理

相关文章

相关课程