第 2 章 Python基础

前面你已经在计算机上安装并运行了 Python,下面我们来学习一些 Python 的基础知识。后续章节的内容都建立在这些概念的基础上,我们需要首先掌握这些概念。

在上一章中,我们利用下面几行代码测试了 Python 的安装是否成功:

  1. import sys
  2. import pprint
  3. pprint.pprint(sys.path)

读完本章,你将会明白上面每一行代码的含义,并学会相关术语,能够说明上述代码的作用。你还将学习 Python 的各种数据类型,对 Python 的入门概念有基本的了解。

我们会讲得比较快,把重点放在学习后续章节时需要知道的内容。后续章节中我们还会根据需要讲一些新概念。我们希望这种方法能让你将这些新概念应用于感兴趣的数据集和问题,并从中学到东西。

首先我们启动 Python 解释器。本章的 Python 代码都在解释器中运行。浏览一遍本章这样的介绍性内容是很容易的,但我们要着重强调动手敲代码的重要性。与学习一门口语类似,在实践中学习是最有效的学习方法。在你输入本书练习代码并运行的过程中,会遇到大量的错误,而调试过程(解决这些错误的过程)会让你学到很多知识。

启动 Python 解释器

在第 1 章里我们学过如何启动 Python 解释器。提醒一下,你首先需要打开命令行工具,然后输入 python(如果你安装了附录 F 中提到的 IPython,也可以输入 iPython):

  1. python

你应该会看到类似这样的输出(注意,提示符已经切换成 Python 解释器的提示符):

  1. Python 2.7.7 (default, Jun 2 2014, 18:55:26)
  2. [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
  3. Type "help", "copyright", "credits" or "license" for more information.
  4. >>>

如果没有特别说明的话,本章后面我们输入的所有内容都是在 Python 解释器中输入的。如果你用的是 IPython,提示符是类似 In [1]: 这样的。

2.1 基本数据类型

本节将学习 Python 中的简单数据类型。这些数据类型都在 Python 的信息处理过程中发挥重要作用。我们要学习的数据类型包括字符串型、整型、浮点型和其他非整数类型。

2.1.1 字符串

我们要学习的第一个数据类型是字符串型。你之前可能没有在这种语境下听过“字符串”这个词,但字符串实际上就是用引号标记的文本。字符串里可以包含数字、字母和符号。

下面都是字符串的例子:

  1. 'cat'
  2. 'This is a string.'
  3. '5'
  4. 'walking'
  5. '$GOObarBaz340 '

将上面任一字符串输入到 Python 解释器里,解释器会返回相同的内容。程序仿佛在说:“嘿,我听到你了。你说的是 'cat'(或任何你输入的内容)。”

只要字符串位于成对的引号(单引号或双引号都可以)之间,其内容无关紧要。字符串的首尾必须用相同的引号(单双均可):

  1. 'cat'
  2. "cat"

上面两个例子在 Python 中的含义是相同的。两种情况下,Python 都会返回单引号的 'cat'。有些人习惯于在代码中使用单引号,另一些人更喜欢用双引号。无论你用哪种引号,重要的是前后风格要保持一致。本书的两位作者更喜欢用单引号,因为输入双引号需要按住 Shift 键。输入单引号可以偷懒。

2.1.2 整数和浮点数

我们要学习的第二种和第三种数据类型是整型和浮点型,这是 Python 中处理数字的方法。首先来看整型。

  • 整数

你可能还记得数学课上学过的整数,但如果你忘记了,整数是指整数(an integer is a whole number)。下面是一些整数的例子:

  1. 10
  2. 1
  3. 0
  4. -1
  5. -10

将上面的整数输入到 Python 解释器里,解释器会返回相同的内容。

注意,上一节的字符串例子中有一个是 '5'。如果输入的数字是在引号中,Python 会将其看作字符串。在下面的例子中,第一个值和第二个值并不相等:

  1. 5
  2. '5'

想测试二者是否相等,可以在解释器中输入:

  1. 5 == '5'

== 符号是用来测试两个值是否相等。测试的返回值是真(True)或假(False)。返回值是另一种 Python 数据类型,叫作布尔型。后面会讲到布尔型,这里先简单学习一下。布尔型可以判断语句是真还是假。在上面的语句中,我们问 Python:整数 5 与字符串 '5' 是否相等?Python 返回了什么?怎样才能让语句的返回值为 True ?(提示:试一下两个都是整数或两个都是字符串的情况!)

你可能想知道,为什么有人会把数字当作字符串来存储。有时是因为使用不当——例如,代码将数字存储成 '5',而实际上应该存储成 5,没有引号。再举一个例子,字段内容是人工填写的,里面可能既包含字符串又包含数字(例如,调查中人们可能输入“五”“5”或“V”)。它们都是数字,但是数字的不同表示方式。在这种情况下,你可能会先把它们存储成字符串,后面再进行处理。

将数字存储为字符串,最常见的原因之一是故意这么做,例如美国邮政编码的存储。美国的邮编共包含五位数字。在新英格兰地区和东北部的其他地方,邮编是以 0 开头的。在 Python 解释器中试着输入波士顿的一个邮编,一次作为字符串输入,一次作为整数输入。出现了什么情况?

  1. '02108'
  2. 02108

在第二个例子中,Python 会抛出一个语法错误[SyntaxError,报错信息为无效的标记(invalid token),并且有一个箭头指向开头的 0]。在 Python 以及许多其他语言中,“标记”(token)是指特殊的单词、符号和标识符。在上面的例子中,Python 不知道如何处理以 0 开头的数(非八进制的数),这意味着它是一个无效的标记。

  • 浮点数、小数和其他非整数类型

Python 处理非整数的运算有许多种方法。如果你不了解每一种非整数数据类型的运算方法,这些方法可能会令人感到困惑,而且似乎引入了舍入误差。

在 Python 中使用非整数时,Python 默认将其转换成浮点数。浮点数的表示方法采用的是各版本 Python 内置的浮点数据类型。也就是说,Python 存储的是该数值的近似值——仅反映特定精度水平的近似值。

在 Python 解释器中输入下面这两个数字,注意二者之间的不同:

  1. 2
  2. 2.0

第一个是整数。第二个是浮点数。我们做点计算,进一步了解这些数字的运算规则,以及 Python 如何对它们进行求值。在 Python 解释器中输入:

  1. 2/3

发生了什么?你得到的返回值是 0,但你可能本来以为会是 0.66666666666666660.6666666666666667 或类似的数字。问题在于,这些数字都是整型,整型无法完成分数运算。我们试着把其中一个数字变成浮点数:

  1. 2.0/3

现在我们得到了更精确的答案:0.6666666666666666。如果输入的数字中有一个是浮点数,计算的结果也是浮点数。

如前文所述,Python 中的浮点数可能会引起精度问题(https://docs.python.org/2/tutorial/floatingpoint.html)。浮点数的运算速度很快,但正是因为这一点,浮点数不够精确。

从原理上来说,Python 与你和计算器对待数字的方式都不同。在 Python 解释器中试试下面这两个例子:

  1. 0.3
  2. 0.1 + 0.2

对于第一行代码,Python 返回 0.3。对于第二行代码,你本来希望返回 0.3,但实际上你得到的返回值是 0.300000000000000040.30.30000000000000004 这两个值并不相等。如果对其中的细微差别感兴趣,可查阅 Python 文档(https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues)了解更多内容。

在本书中,需要考虑精度问题时,我们将使用 decimal 模块(或库,https://docs.python.org/2/library/decimal.html)。模块是可导入使用的代码段或代码库。decimal 模块可以让数字(整数或浮点数)的运算结果符合预期(与你在数学课上学到的概念一致)。

在下面的例子中,第一行代码从 decimal 模块中导入了 getcontextDecimal,这样我们就可以在解释器环境中使用它们。接下来的两行代码利用 getcontextDecimal 来做之前用浮点数做过的数学运算:

  1. from decimal import getcontext, Decimal
  2. getcontext().prec = 1
  3. Decimal(0.1) + Decimal(0.2)

运行上面的代码,Python 会返回 Decimal('0.3')。现在你输入 print Decimal(0.3),Python 会返回 0.3,这也正是我们本来希望看到的值(而不是 0.30000000000000004)。

我们来一行一行地阅读这三行代码:

  1. from decimal import getcontext, Decimal
  2. getcontext().prec = 1
  3. Decimal(0.1) + Decimal(0.2)

❶ 从 decimal 模块中导入 getcontextDecimal

❷ 将舍入精度设定为一位小数。decimal 模块将大部分的舍入和精度设置保存在默认的上下文(context)中。本行代码将上下文的精度改成只保留一位小数。

❸ 对两个小数(一个值为 0.1,一个值为 0.2)求和。

如果修改 getcontext().prec 的值会怎么样?动手试一下,然后重新运行最后一行代码。你应该会看到不一样的结果,这取决于你设置的是保留几位小数。

如前文所述,在数据处理过程中你会遇到许多数学上的细节问题。你可能需要完成的数学运算也有许多不同的方法,但在用到非整数时,使用小数型数据可以使计算精度更高。

Python 中的数字

Python 中的数字类型有不同的精度水平,这是 Python 语言的缺点之一。随着对数据处理的深入学习,我们将在本书中学到更多 Python 中与数字和数学相关的库。要是你现在就想知道,并且打算做一些不那么基础的数学运算,下面是一些你需要熟悉的 Python 库。

我们已经学过了字符串型、整型和浮点型 / 小数型。下面以这些基本数据类型为基础,创建更复杂的数据类型。

2.2 数据容器

本节会讲到数据容器,里面装有许多数据点(data point)。但应该注意的是,这些容器本身也是 Python 的数据类型。Python 中有几种常见的容器:变量、列表和字典。

2.2.1 变量

变量为我们提供了保存数据的方法,这些数据包括字符串、数字或其他数据容器。变量由一串字符组成,通常是一个小写单词(或用下划线连接的多个单词),用来说明变量包含的内容。

我们试着创建一个简单的变量。在 Python 解释器中,试试下面的代码:

  1. filename = 'budget.csv'

输入正确的话,解释器应该不会返回任何值。这与在 Python 解释器中输入字符串有所不同。如果在 Python 解释器中只输入 'budget.csv',它会输出 'budget.csv'

当你创建一个变量时,是将程序本来应该输出的数据赋值给这个变量。这也是创建新变量时没有返回值的原因。在上面的例子中,我们的变量叫作 filename,其中保存着我们输入的字符串('budget.csv'),作为它的值。

面向对象编程

你可能听说过面向对象编程(object-oriented programming,OOP)。Python 是一门面向对象的编程语言。“面向对象编程”中的“对象”可以是本章我们学过的任意一种数据类型,例如字符串、变量、数字或浮点数。

在正文给出的例子中,我们的对象是一个字符串,此时保存在 filename 中。我们定义的每一个变量都是一个 Python 对象。在 Python 中,我们用对象来保存后面要用到的数据。这些对象通常具有不同的性质和行为,但它们都是对象。

例如,每一个整数对象都可以用 + 号(加法运算符)与另一个整数相加。继续学习 Python 的过程中,你会学到关于这些对象及其基础类型的性质和行为的更多内容,也会因此喜欢上面向对象编程的!

前面在创建一串字母并将其赋值给名为 filename 的变量时,我们遵循了变量命名的几条通用规则。不用担心记不住这些规则,但如果在代码中定义新变量时出现错误,一定要想起这些规则。

  • 可以包含下划线,但不能包含连字符。

  • 可以包含数字,但变量名不能以数字开头。

  • 为了方便阅读,单词用小写字母,单词之间用下划线隔开。

试一试下面的代码:

  1. 1example = 'This is going to break.'

发生了什么?你得到了什么类型的错误?你应该得到的是语法错误,因为你违反了第二条规则。

只要不违反 Python 变量命名的规则,变量几乎可以任意命名。例如:

  1. horriblevariablenamesarenotdescriptiveandtoolong = 'budget.csv'

可以看出,变量名太长,并且没有对变量内容进行说明。另外,缺少下划线,让人难以读懂。什么样的变量名是一个好的变量名?问自己一个问题:六个月之后,如果我已经把代码全部忘记了,什么样的变量名仍是有意义的,并能帮我理解代码的内容?

我们来看一个更合理的变量名——cats。如前一个例子所示,变量的值不一定要是文件名。

变量可以有许多不同的值和名字。我们假装在数猫咪的数量,所以要把一个整数赋值给变量 cats

  1. cats = 42

如果 Python 脚本记录了我们有多少只猫咪,我们不需要每时每刻都知道确切的数字。我们只需要知道这个值被保存在变量 cats 中,所以,当我们在解释器中调用 cats 时,或者在另一段代码中用到 cats 时,它总会返回当前猫咪的数量。

调用变量,是指请求 Python 返回该变量的值。我们来调用 cats。在解释器中输入 cats。你应该会得到 42 作为返回值。如果输入 filename,你应该会得到字符串 'budget.csv' 作为返回值。在计算机上试一下:

  1. >>> cats
  2. 42
  3. >>> filename
  4. 'budget.csv'
  5. >>>

如果输入不存在的变量名(或者输错了变量名),你会得到以下错误:

  1. >>> dogs
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. NameError: name 'dogs' is not defined

前面说过,学会如何阅读错误信息是很重要的,这可以让你明白犯了什么错误,以及如何改正错误。在这个例子中,错误信息指出,dogs is not defined,意思是我们没有定义过一个叫作 dogs 的变量。由于我们没有定义过这个变量,所以 Python 不知道我们要调用的是什么。

在第一个例子中,如果你忘了在 'budgets.csv' 上加引号,也会得到相同的错误。在 Python 解释器中试一下:

  1. filename = budget.csv

返回的错误信息是 NameError: name 'budget' is not defined。这是因为 Python 并不知道 budget.csv 应该是一个字符串。要记住,字符串总是用引号来标记。没有引号的话, Python 会试图将其解释成另一个变量。这个练习的要点就是,注意错误发生在哪一行,并问问自己:错误可能出在哪里?在 dogs 的例子中,错误信息指出,错误发生在第 1 行。如果有很多行代码,错误信息可能会指向第 87 行。

前面给出的所有例子都是短字符串或整数。变量也可以保存长字符串,甚至是跨很多行的字符串。在例子中我们选择用短字符串,是因为对你(或我们)来说,输入长字符串一点都不好玩。

试一下保存长字符串的变量。注意,字符串里含有单引号,我们必须用双引号来保存:

  1. recipe = "A recipe isn't just a list of ingredients."

现在输入 recipe,你会得到保存的长字符串:

  1. >>>recipe
  2. "A recipe isn't just a list of ingredients."

变量的数据类型不一定要是字符串或整数。变量可以保存各种不同的 Python 数据类型,我们会在后续章节进一步学习这方面的内容。

2.2.2 列表

列表是具有某种共同关系的一组值。在 Python 中使用列表,和在日常语言中使用列表很相似。在 Python 中,将一列元素放到方括号([])中,元素之间用逗号隔开,即可创建列表。

我们在 Python 中创建一个食品的列表:

  1. ['milk', 'lettuce', 'eggs']

第 2 章 Python基础 - 图1 上面这个列表由字符串组成,不是由变量组成。这一点是可以看出来的,因为单词都用引号包裹。如果元素都是变量的话,是不会有两边的引号的。

按下 Return 键,Python 会返回以下内容:

  1. ['milk', 'lettuce', 'eggs']

你刚刚创建了第一个 Python 列表:字符串列表。你可以创建任意数据类型的列表,或者多种数据类型混合的列表(例如,同时包含浮点数和字符串的列表)。我们来创建一个同时包含整数和浮点数的列表:

  1. [0, 1.0, 5, 10.0]

下面将我们的列表保存在变量中,这样就可以在后面的代码中调用它。变量很有用,因为变量可以让我们不必反复输入数据。如果列表很长,比如说有 5000 个元素那么长,手动输入数据很容易出错,而且效率不高。正如前文所述,变量是保存值的方法,将其保存在合理命名的容器中。

在 Python 解释器中尝试以下代码:

  1. shopping_list = ['milk', 'lettuce', 'eggs']

按下 Return 键,你应该会看到新的一行。看起来似乎什么也没有发生。之前是将列表原样返回,还记得吗?现在 Python 将列表保存在 shopping_list 变量中。如果在 Python 提示符中输入 shopping_list 来调用变量,你应该会得到以下返回值:

  1. shopping_list
  2. ['milk', 'lettuce', 'eggs']

列表也可以保存变量。比如说,我们有一个变量,里面保存的是动物收容所中动物的数量:

  1. cats = 2
  2. dogs = 5
  3. horses = 1

现在可以将这些动物的数量放在一个列表中:

  1. animal_counts = [cats, dogs, horses]

在 Python 解释器中输入 animal_counts,Python 会返回下面的值:

  1. [2, 5, 1]

变量为我们保存信息。当我们输入变量名时,Python 返回的是变量中保存的值。

你还可以创建包含列表的列表。比如说,创建动物名字的列表:

  1. cat_names = ['Walter', 'Ra']
  2. dog_names = ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido']
  3. horse_names = ['Mr. Ed']
  4. animal_names = [cat_names, dog_names, horse_names]

在 Python 解释器中输入 animal_names,Python 会返回下面的值:

  1. [['Walter', 'Ra'], ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido'], ['Mr. Ed']]

你不必输入所有的名字来创建包含列表的列表。原始变量(cat_names, dog_names, horse_names)也是列表,它们仍然可用。例如,输入 cat_names,你会得到 ['Walter', 'Ra'] 作为返回值。

前面已经探索了列表,下面我们继续探索一个稍微复杂一点的数据容器,叫作字典。

2.2.3 字典

字典比变量或列表更加复杂。“字典”这个名字是很贴切的。将 Python 的字典看作传统意义上的字典——用来查找单词释义的工具。在 Python 的字典中,你要查找的单词叫作(key),这些单词的释义叫作(value)。在 Python 中,键对应一个值。

回头看动物的例子。animal_numbers 保存的是我们拥有的不同动物数量的列表,但我们不清楚哪个数字对应哪一种动物。字典是存储这种信息的好方法。

在下面的例子中,我们用动物种类作为键,每种动物的数量作为值:

  1. animal_counts = {'cats': 2, 'dogs': 5, 'horses': 1}

如果想用键来访问一个值,可以从字典中访问键(类似在普通的字典中查单词)。为了在 Python 中实现这样的查找(比如查找我们拥有的狗狗的数量),可以输入以下代码:

  1. animal_counts['dogs']

你应该看到的返回值是 5,因为我们在字典中('dogs': 5)设置 'dogs' 键对应的值是 5。如你所见,想要存储匹配的键值对时,字典是很有用的。根据你的需求不同,字典可以是非常强大的,所以我们进一步研究同时使用列表和字典。

对于前面动物名字的列表,很难说清楚哪个名字列表属于哪一种动物。哪个列表里面是猫咪的名字,哪个列表里面是狗狗的名字,哪个列表里面是马的名字,谁也搞不清楚。但是,我们可以用字典把动物们区分清楚:

  1. animal_names = {
  2. 'cats': ['Walter', 'Ra'],
  3. 'dogs': ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido'],
  4. 'horses': ['Mr. Ed']
  5. }

存储同样的值还有另一种方法,它用到了更多的变量:

  1. cat_names = ['Walter', 'Ra']
  2. dog_names = ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido']
  3. horse_names = ['Mr. Ed']
  4. animal_names = {
  5. 'cats': cat_names,
  6. 'dogs': dog_names,
  7. 'horses': horse_names
  8. }

❶ 这一行代码将变量 cat_names 定义为猫咪名字的列表(字符串列表)。

❷ 这一行代码使用变量 cat_names,传递猫咪名字的列表作为字典中键 'cats' 对应的值。

虽然过程有所不同,但两种方法得到的是相同的字典 1。随着对 Python 的深入学习,你将能够更好地判断,什么时候需要定义更多的变量,什么时候不这么做反而更好。现在你会发现,利用许多定义好的不同变量(例如 cat_namesdog_names)来创建新的变量(例如 animal_names),这是很容易的。

1两个字典并不完全相同,因为第二个字典中使用了可以被修改的对象。想详细了解二者的区别,请查阅附录 E。

第 2 章 Python基础 - 图2 虽然 Python 有间距和格式的规则,但你的字典格式不一定非得和我们前面的一样。但是,你的代码应该尽可能易于阅读。保证代码的可读性,你自己以及其他合作的开发者都会因为这一点而感谢你的。

2.3 各种数据类型的用途

每种基本数据类型都可以做各种各样的事情。下面列出了我们目前学过的数据类型,并举例说明这些数据类型所能做的各种事情。

  • 字符串

    • 大小写转换

    • 删除字符串末尾的空格

    • 分割字符串

  • 整数和小数

    • 加减运算

    • 简单数学运算

  • 列表

    • 在列表中增加或删除元素

    • 删除列表的最后一个元素

    • 列表重新排列

    • 列表排序

  • 字典

    • 增加一个键 / 值对

    • 将指定的键设置为新的值

    • 利用键查找值

第 2 章 Python基础 - 图3 在上面这个列表中我们故意没有提到变量。变量能做的事情取决于它包含的数据。比如说,如果变量是一个字符串,那么它可以做所有字符串能做的事情。如果变量是一个列表,那么它可以做只有列表才能做的各种事情。

把数据类型看作名词,把它们能做的事情看作动词。在大多数情况下,数据类型能做的事情被称为方法(method)。想要访问数据类型的方法,或者说让数据类型做一些事情,你可以用点号(.)。比如说,如果你将一个字符串赋值给名为 foo 的变量,你可以输入 foo. strip() 来调用该字符串的 strip 方法。我们来看一下其中一些方法的作用。

第 2 章 Python基础 - 图4 在调用字符串的方法时,它们的行为是 Python 默认库的一部分(类似于手机上预装的默认应用),所有 Python 版本共享这一默认库。在每一台运行 Python 的计算机上都可以调用这些方法,因此每一个 Python 字符串都可以共享相同的方法(就像每一台手机都可以打电话,每一台苹果手机都可以发送 iMessage 一样)。Python 标准库(也叫作 stdlib,https://docs.python.org/2/library/)中包含了大量的内置方法和基本数据类型,其中包括你正在使用的 Python 数据类型。

2.3.1 字符串方法:字符串能做什么

回头看最开始定义的变量 filename。我们开始时用 filename = 'budget.csv' 来定义变量。这种定义方法很方便。但有些时候,事情并没有那么简单。来看几个例子:

  1. filename = 'budget.csv '

注意,现在 filiname 字符串里有许多多余的空格,可能需要将其删掉。可以用 Python 字符串的 strip 方法,这是一个内置函数,可以从头到尾删除字符串中多余的空格:

  1. filename = 'budget.csv '
  2. filename = filename.strip()

第 2 章 Python基础 - 图5 如果你没有对变量重新赋值的话(令 filename 等于 filename.strip() 的输出值),你对 filename 所做的修改不会被保存。

在 Python 解释器中输入 filename,现在你应该可以看到,空格已经被删除。

比如说,文件名需要全部用大写字母。可以用 Python 字符串内置的 upper 函数将所有的字母转换成大写:

  1. filename = 'budget.csv'
  2. filename.upper()

从输出应该可以看出,现在文件名已经全部大写了:

  1. 'BUDGET.CSV'

在这个例子中,我们没有将大写的字符串重新赋值给变量 filename。在解释器中再次调用 filename 时会发生什么?输出应该还是 'budget.csv'。如果你不希望修改你的变量,只想对变量进行转换后使用一次,可以调用类似 upper 这样的方法,这些方法会返回修改后的字符串,但不会改变变量本身。

如果想对变量重新赋值,用同一个变量名保存返回值,应该怎么办呢?接下来,将变量 filename 的值改成全部大写:

  1. filename = 'budget.csv'
  2. filename = filename.upper()

❶ 在本行之后调用 filename,输出是 'budget.csv'

❷ 在本行之后调用 filename,输出是 'BUDGET.CSV'。可以将代码压缩成一行来运行:

  1. filename = 'budget.csv'.upper()

代码的行数有时是你个人的风格或偏好。你可以随意选择你认为合理的方式,但要保持代码清晰、易读、明了。

在上面这些例子中只讲了两个字符串方法:stripupper,但还有许多其他的内置字符串方法。随着在数据处理过程中遇到更多的字符串,我们会学习更多的字符串方法。

2.3.2 数值方法:数字能做什么

整数和浮点数 / 小数都是数学对象。如果你输入 40 + 2,Python 会返回 42。如果你想把结果保存在变量中,可以将其赋值给一个变量,正如我们在字符串的例子中所做的那样:

  1. answer = 40 + 2

现在你输入 answer,得到的返回值是 42。整数能做的大部分事情都是可以预知的,但有可能你需要使用一些特殊的格式,这样 Python 解释器才能理解你想做的数学运算。例如,如果你想计算 42 的平方,那你需要输入 42**2

整数、浮点数和小数也还有许多其他的方法,我们会在学习数据处理的过程中遇到其中一些方法。

加法和减法

对于 Python 的其他数据类型,你也可以做加法,例如字符串和列表。试一试下面的代码:

  1. 'This is ' + 'awesome.'

  1. ['Joker', 'Simon', 'Ellie'] + ['Lishka', 'Turtle']

试试用减法,看看会发生什么?运行下面的代码会报错,你能从中学到什么?

  1. ['Joker', 'Simon', 'Ellie', 'Lishka', 'Turtle'] - ['Turtle']

你应该会得到报错信息:TypeError: unsupported operand type(s) for -: 'list' and 'list'。这告诉我们,Python 列表支持加法,却不支持减法。这是因为Python 开发人员对每种数据类型支持的方法所做的选择。如果你想了解如何对列表做减法,可以查看 Python 官网上列表的 remove 方法(https://docs.python.org/2/tutorial/datastructures.html)。

2.3.3 列表方法:列表能做什么

列表有几个必须知道的方法。我们从一个空列表开始,用一个方法来添加元素。

首先,像这样定义一个空列表:

  1. dog_names = []

在解释器中输入 dog_names,返回的是 [],这是 Python 显示空列表的方式。在本章前面的内容里,这个变量中保存了好几个名字,但在上一行代码中我们重新定义了这个变量,现在它是一个空列表。内置的 append 方法可以向列表中添加元素。现在利用这一方法将“Joker”添加到列表中:

  1. dog_names.append('Joker')

现在输入 dog_names,返回的列表中将包含一个元素:['Joker']

下面你自己来操作,利用 append 方法创建这样的列表:

  1. ['Joker', 'Simon', 'Ellie', 'Lishka', 'Turtle']

比如说,你不小心添加了一个猫咪的名字,'Walter'

  1. dog_names.append('Walter')

你可以利用 Python 列表内置的 remove 方法删除这个元素:

  1. dog_names.remove('Walter')

列表还有许多其他的内置方法,但 appendremove 是其中最常用的两个。

2.3.4 字典方法:字典能做什么

为了学习一些有用的字典方法,我们来从头创建一个动物数量的字典。

在下面的例子中,我们创建了一个空的字典。然后添加了一个键,并给定了这个键对应的值:

  1. animal_counts = {}
  2. animal_counts['horses'] = 1

向字典添加元素(animal_counts['horses'])与向列表添加元素略有不同。这是因为字典既有键又有值。在上面的例子中,键是 'horses',值是 1

我们用动物数量来定义字典的其他部分:

  1. animal_counts['cats'] = 2
  2. animal_counts['dogs'] = 5
  3. animal_counts['snakes'] = 0

现在在 Python 解释器中输入 animal_counts,你应该会得到以下字典:{'horses': 1, 'cats': 2, 'dogs': 5, 'snakes': 0}。(Python 字典不会保存元素的顺序,所以你看到的输出可能会有所不同,但应该包含相同的键值对)。

这里讲的是一个非常小的例子,但是编程并非总是这样方便。试想由世界上所有家畜的数量构成的字典。作为程序员,我们可能不知道这个 animal_counts 字典中包含的所有动物种类。在处理一无所知的大型字典时,我们可以利用字典方法来了解字典的更多内容。下面这个命令返回字典包含的所有键:

  1. animal_counts.keys()

如果你把前面的练习都做了,那么在解释器中输入上面的代码会返回一个键的列表,如下所示:

  1. ['horses', 'cats', 'dogs', 'snakes']

对于上面任何一个键,你可以从字典中检索到与其对应的值。下面的查询将返回狗狗的数量:

  1. animal_counts['dogs']

这行代码的输出是 5

如果你愿意,可以将这个值保存在一个新变量中,这样你就无需再次查询:

  1. dogs = animal_counts['dogs']

现在,你直接输入变量 dogs,Python 将返回 5

这就是你可以对字典做的一些基本操作。随着用代码去解决越来越复杂的问题,我们也会更深入地学习字典,正如字符串和列表一样。

2.4 有用的工具:typedirhelp

Python 标准库中有几个内置工具,可以帮你确定变量的数据类型或对象类型,并给出这些变量能做的事情(即它们都有哪些方法)。本节将学习三个工具,它们都是 Python 标准库的一部分。

2.4.1 type

type 可以帮你确定你的对象属于哪种数据类型。想在 Python 代码中做到这一点,将变量放到 type() 的括号里,例如,如果变量名是 dogs,那就在 Python 提示符后输入 type(dogs)。当你用变量保存数据,并想知道变量里的数据是什么类型时,这一方法是非常有用的。回忆本章前面邮政编码的例子。

对于值 20011,这里有两种不同的用法。在第一个例子中,它是保存成字符串的邮编。在第二个例子中,它是一个整数:

  1. '20011'
  2. 20011

如果将这两个值保存在变量中,将更难以确定变量的类型,我们可能不知道或不记得用的是字符串还是整数。

如果将值传递给内置方法 type,Python 就会告诉我们对象属于那种数据类型。试一下:

  1. type('20011')
  2. type(20011)

第一行返回的是 str,第二行返回的是 int。将列表传递给 type 会返回什么?变量呢?

在你试图排查错误时,或者运行其他人的代码时,确定对象的类型是很有用的。还记得我们试图从一个列表中减去另一个列表吗(见 2.3.2 节)?好吧,你也不能从一个字符串中减去另一个字符串。所以,与整数 20011 相比,字符串 '20011' 具有许多不同的方法以及用例。

2.4.2 dir

dir 会返回一个内置方法与属性的列表,帮你列出特定数据类型能做的所有事情。我们用字符串 'cat,dog,horse' 来试一下:

  1. dir('cat,dog,horse')

暂时忽略返回的列表中开头的那些项(以双下划线开头的那些字符串)。这些是 Python 使用的内部方法或私有方法

最有用的方法包含在返回列表的第二部分。许多方法的用途显而易见,或者说是自说明的(self-documenting)。你应该会看到本章前面使用的一些字符串方法:

  1. [...,
  2. '__sizeof__',
  3. '__str__',
  4. '__subclasshook__',
  5. 'formatterfield_name_split',
  6. 'formatterparser',
  7. 'capitalize',
  8. 'center',
  9. 'count',
  10. 'decode',
  11. 'encode',
  12. 'endswith',
  13. 'expandtabs',
  14. 'find',
  15. 'format',
  16. 'index',
  17. 'isalnum',
  18. 'isalpha',
  19. 'isdigit',
  20. 'islower',
  21. 'isspace',
  22. 'istitle',
  23. 'isupper',
  24. 'join',
  25. 'ljust',
  26. 'lower',
  27. 'lstrip',
  28. 'partition',
  29. 'replace',
  30. 'rfind',
  31. 'rindex',
  32. 'rjust',
  33. 'rpartition',
  34. 'rsplit',
  35. 'rstrip',
  36. 'split',
  37. 'splitlines',
  38. 'startswith',
  39. 'strip',
  40. 'swapcase',
  41. 'title',
  42. 'translate',
  43. 'upper',
  44. 'zfill']

看一下字符串 'cat,dog,horse',它看起来像是保存在字符串里的列表。实际上它是单一值,但利用 Python 字符串内置的 split 方法,我们可以以逗号为分隔符,将字符串切分成更小的字符串,像这样:

  1. 'cat,dog,horse'.split(',')

Python 将返回一个列表:

  1. ['cat', 'dog', 'horse']

下面对这个列表调用 dir 函数:

  1. dir(['cat', 'dog', 'horse'])

和字符串相比,列表可选的方法没有那么多,但我们来尝试其中几个。首先,将列表转化为变量。你现在应该知道如何将列表赋值给变量,这是一个例子:

  1. animals = ['cat', 'dog', 'horse']

前面用 dir 作用在列表上给出了许多新方法,现在在变量 animals 上试用其中一些方法:

  1. animals.reverse()
  2. animals.sort()

运行每一行代码后,打印输出 animals 的值,这样你就能看出这些方法是如何改变列表的。你预期的输出是什么样的?它与你看到的相同吗?尝试将 dir 方法作用在整数和浮点数上。(提示:dir 只能传入一个对象,所以试着输入 dir(1)dir(3.0))。其中有没有你没有想到的方法?

如你所见,dir 可以让你深入了解每一种 Python 数据类型的内置方法。在利用 Python 进行数据处理时,这些方法是很有价值的。建议你花时间对感兴趣的上表列出的方法都尝试一下,并用不同的数据类型测试更多的方法。

2.4.3 help

本章要学习的第三个有用的 Python 内置方法是 help 方法。这一方法会返回对象、方法或模块的文档——虽然经常以技术性很强(有时很难懂)的文字书写。来看一下 split 方法的帮助文档,这是我们在前一节用过的方法。如果你不知道需要将字符串的分隔符放在括号内,怎么能知道如何使用 Python 字符串的 split 方法呢?假设我们不知道如何使用 split,不传入 ',' 来调用这一方法:

  1. animals = 'cat,dog,horse'
  2. animals.split()

代码的返回值如下:

  1. ['cat,dog,horse']

看起来不错,对吧?但经不起仔细观察。正如我们所见,Python 将字符串转换成一个列表,但并没有利用逗号对多个单词进行分割。这是因为内置的 split 方法默认按空格分割字符串,不是按逗号分割。我们需要在方法中传入一个逗号字符串(','),来告诉 Python 按逗号对字符串进行分割。

为了帮助理解这个方法是如何工作的,我们将其传递给 help。前面把变量 animals 变成了列表,所以首先我们必须重新定义这个变量。我们把它变回字符串,然后查看 split 的工作原理:

  1. animals = 'cat,dog,horse'
  2. help(animals.split)

❶ 本行代码将 animals.split(没有 ())传递给 help 方法。你可以向 help 方法中传入任何对象、方法或模块,但如前所见,在传入方法时不应该把尾部的括号也包括进去。

Python 的返回值如下:

  1. split(...)
  2. S.split([sep [,maxsplit]]) -> list of strings
  3. Return a list of the words in the string S, using sep as the
  4. delimiter string. If maxsplit is given, at most maxsplit
  5. splits are done. If sep is not specified or is None, any
  6. whitespace string is a separator and empty strings are removed
  7. from the result.

帮助文档的第一行说的是:S.split([sep [,maxsplit]])list of strings。翻译成汉语,这告诉我们,对于字符串(S),我们有一个方法(split)、第一个可选参数(也就是可以传入的对象)sep 以及第二个可选参数 maxsplit。参数名两边的方括号([])表明它们是可选的,不是必需的。这个方法返回(->)一个字符串列表。

下一行说的是:"Return a list of the words in the string Susing sep as the delimiter string." sep 是被传入 split 方法的参数,作用是分隔符(seperator)。分隔符(delimiter)是用来分割字段的单个字符或一串字符。例如,在一个逗号分隔文件中,逗号就是分隔符。逗号还是我们所创建字符串的分隔符,因为它把我们希望出现在列表中的单词分隔开。

第 2 章 Python基础 - 图6 阅读完帮助文档后(利用方向键上下翻页),你可以输入 q 退出 help

help 文档还告诉我们,如果没有指定其他分隔符,默认的分隔符是空白。这告诉我们,如果我们有一个字符串 'cat dog horse'split 方法不需要我们在 () 内传入分隔符。如你所见,内置的 help 函数可以告诉你许多关于如何使用某个方法的内容,还可以告诉你这个方法是否适合你正在解决的问题。

2.5 综合运用

我们利用刚学到的新技术来做一个测验。试着完成以下内容。

(1) 创建一个字符串、一个列表和一个字典。

(2) 利用 dir 方法查找每种数据类型可用的方法。

(3) 试用一些你发现的内置方法,直到某个方法抛出了错误。

(4) 利用 help 查看该方法的文档。试着理解这个方法是做什么的,并试着搞清楚,为了让这个方法正常运行,你可能还需要做些什么。

恭喜!你刚刚学会了如何编程。编程不是死记硬背,相反,编程是在出错时排查并解决错误。

2.6 代码的含义

在本章开头我们承诺过,在本章结束时你会理解这三行代码:

  1. import sys
  2. import pprint
  3. pprint.pprint(sys.path)

根据目前所学的内容,我们把这三行代码分开来看。在 2.1.2 节中,我们导入了 decimal 库。看起来我们正从 Python 标准库中导入两个模块——syspprint

看一下这些模块的帮助文档(一定要确定你已经导入了这些模块,否则 help 会抛出错误!)。由于 pprint 更容易读懂,我们先来看它的帮助文档:

  1. >>>import pprint
  2. >>>help(pprint.pprint)
  3. Help on function pprint in module pprint:
  4. pprint(object, stream=None, indent=1, width=80, depth=None)
  5. Pretty-print a Python object to a stream [default is sys.stdout].

很好。根据 pprint.pprint() 的文档,这个方法将传入的内容以易读的形式显示出来。

在上一章中我们学过,sys.path 给出 Python 寻找模块的位置。sys.path 的数据类型是什么?

  1. import sys
  2. type(sys.path)

是列表。我们知道列表怎么用!现在我们还知道,将一个列表传入 pprint.pprint,列表的输出格式会非常美观。我们把它用在包含列表的列表上,里面保存的是动物名字。首先,再多加一些名字,使列表变得很乱:

  1. animal_names = [
  2. ['Walter', 'Ra', 'Fluffy', 'Killer'],
  3. ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido'],
  4. ['Mr. Ed', 'Peter', 'Rocket','Star']
  5. ]

下面将 pprint 作用于变量 animal_names:

  1. pprint.pprint(animal_names)

得到的返回值如下:

  1. [['Walter', 'Ra', 'Fluffy', 'Killer'],
  2. ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido'],
  3. ['Mr. Ed', 'Peter', 'Rocket', 'Star']]

总结一下,这是最开始这三行代码每一行的作用:

  1. import sys
  2. import pprint
  3. pprint.pprint(sys.path)

❶ 导入 Python 的 sys 模块。

❷ 导入 Python 的 pprint 模块。

❸ 将列表 sys.path 传递给 pprint.pprint,将列表清晰易读地显示出来。

如果将字典传入 pprint.pprint 会怎么样?你应该会看到格式优美的字典输出。

2.7 小结

数据类型和容器是 Python 理解并存储数据的方式。数据类型有许多种,本章只学习了其中重要的几种,如表 2-1 所示。

表2-1:数据类型

名称 举例
字符串 'Joker'
整数 2
浮点数 2.0
变量 animal_names
列表 ['Joker', 'Simon', 'Ellie', 'Lishka', 'Fido']
字典 {'cats': 2, 'dogs': 5, 'horses': 1, 'snakes': 0}

如你所知,有些数据类型可以包含在其他数据类型之中。列表可以是许多字符串或整数,或二者都有。变量可以是列表、字典、字符串或小数。看一下变量 animal_names,列表也可以是包含列表的列表。随着我们学习更多的 Python 知识,也会更深入地学习这些数据类型、它们的工作原理,以及如何利用它们来满足我们数据处理的需求。

本章我们还学习了 Python 的内置方法,以及能用对象所做的事情。另外,我们学习了几个简单的 Python 方法和工具。利用这些方法和工具,我们可以判断对象的数据类型及其用途。表 2-2 对这些工具做了总结。

表2-2:辅助工具

举例 用途
type('Joker') 返回 'Joker' 的对象类型
dir('Joker') 返回一个列表,给出对象 'Joker' 可以做的所有事情(方法和属性)
help('Joker'.strip) 返回给定方法(在本例中是 strip)的说明文档,以便我们更好地了解如何使用它

下一章我们将学习如何打开各种文件类型,以及如何将数据存储成本章学过的 Python 数据类型。通过将文件中的数据转换成 Python 对象,我们可以充分发挥 Python 的威力,数据处理将很快变成一件容易的事情。