您当前位置:首页 ‣ 深入 Python 3 ‣
难度等级:♦♦♢♢♢
❝ 奇迹是所有哲学的基石,探索是其进程,无知是其终点。 ❞
— 米歇尔·德·蒙田
数据类型。先把第一个 Python 程序放一边,让我们谈谈数据类型。在 Python 中,每个值都有一个数据类型,但您不需要声明变量的数据类型。这是怎么运作的?根据每个变量的初始赋值,Python 会判断它的类型,并在内部进行跟踪。
Python 有许多原生数据类型。以下是重要的类型:
True
,要么是 False
。1
和 2
)、浮点数(1.1
和 1.2
)、分数(1/2
和 2/3
),甚至可以是复数。当然,除了这些类型之外还有其他类型。在 Python 中,一切都是对象,因此还有像模块、函数、类、方法、文件,甚至编译代码这样的类型。您已经见过其中的一些了:模块有名称,函数有 docstrings
,等等。您将在类和迭代器中了解类,在文件中了解文件。
字符串和字节非常重要——而且非常复杂——因此它们拥有自己的章节。让我们先看看其他类型。
⁂
布尔值要么是真,要么是假。Python 有两个常量,巧妙地命名为 True
和 False
,它们可以用于直接分配布尔值。表达式也可以计算为布尔值。在某些地方(例如 if
语句),Python 期望表达式计算为布尔值。这些地方被称为布尔上下文。您可以在布尔上下文中使用几乎任何表达式,Python 将尝试确定其真值。不同的数据类型在布尔上下文中哪些值是真或假方面有不同的规则。(当您在本节后面看到一些具体示例时,这一点就会变得更加清晰。)
例如,请看来自humansize.py
的这段代码片段:
if size < 0:
raise ValueError('number must be non-negative')
size 是一个整数,0 是一个整数,<
是一个数值运算符。表达式 size < 0
的结果始终是一个布尔值。您可以在 Python 交互式 shell 中自行测试这一点
>>> size = 1 >>> size < 0 False >>> size = 0 >>> size < 0 False >>> size = -1 >>> size < 0 True
由于 Python 2 中遗留的一些问题,布尔值可以被视为数字。True
是 1
;False
是 0。
>>> True + True 2 >>> True - False 1 >>> True * False 0 >>> True / False Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: int division or modulo by zero
哎哟,哎哟,哎哟!不要这样做。忘掉我甚至提过它吧。
⁂
数字太棒了。有太多选择。Python 支持整数和浮点数。没有类型声明来区分它们;Python 通过有无小数点来区分它们。
>>> type(1) ① <class 'int'> >>> isinstance(1, int) ② True >>> 1 + 1 ③ 2 >>> 1 + 1.0 ④ 2.0 >>> type(2.0) <class 'float'>
type()
函数检查任何值或变量的类型。正如您可能预期的那样,1
是一个 int
。isinstance()
函数检查值或变量是否为给定类型。int
加到一个 int
会得到一个 int
。int
加到一个 float
会得到一个 float
。Python 会将 int
强制转换为 float
以执行加法,然后返回一个 float
作为结果。正如您刚刚看到的,一些运算符(例如加法)会根据需要将整数强制转换为浮点数。您也可以自己强制转换它们。
>>> float(2) ① 2.0 >>> int(2.0) ② 2 >>> int(2.5) ③ 2 >>> int(-2.5) ④ -2 >>> 1.12345678901234567890 ⑤ 1.1234567890123457 >>> type(1000000000000000) ⑥ <class 'int'>
float()
函数来显式地将 int
强制转换为 float
。int()
函数来将 float
强制转换为 int
。int()
函数会截断,而不是四舍五入。int()
函数会将负数截断至 0。它是一个真正的截断函数,而不是地板函数。☞Python 2 中有
int
和long
的单独类型。int
数据类型受sys.maxint
的限制,它因平台而异,但通常是232-1
。Python 3 只有一个整数类型,它的行为与 Python 2 中旧的long
类型基本一致。有关详细信息,请参见 PEP 237。
您可以对数字进行各种操作。
>>> 11 / 2 ① 5.5 >>> 11 // 2 ② 5 >>> −11 // 2 ③ −6 >>> 11.0 // 2 ④ 5.0 >>> 11 ** 2 ⑤ 121 >>> 11 % 2 ⑥ 1
/
运算符执行浮点数除法。即使分子和分母都是 int
,它也会返回一个 float
。//
运算符执行一种奇怪的整数除法。当结果为正时,您可以将其视为截断(而不是四舍五入)到 0 位小数,但要注意这一点。//
运算符会向上舍入到最接近的整数。从数学角度来说,它是在向下舍入,因为 −6
小于 −5
,但如果您期望它截断到 −5
,则可能会误导您。//
运算符并不总是返回一个整数。如果分子或分母是 float
,它仍然会四舍五入到最接近的整数,但实际返回值将是一个 float
。**
运算符表示“乘方”。112
是 121
。%
运算符给出进行整数除法后的余数。11
除以 2
等于 5
,余数为 1
,因此这里的结果为 1
。☞在 Python 2 中,
/
运算符通常表示整数除法,但您可以通过在代码中包含一个特殊指令使其表现得像浮点数除法。在 Python 3 中,/
运算符始终表示浮点数除法。有关详细信息,请参见 PEP 238。
Python 不仅限于整数和浮点数。它还可以进行您在高中学习过的所有那些花哨的数学运算,并且很快就忘记了。
>>> import fractions ① >>> x = fractions.Fraction(1, 3) ② >>> x Fraction(1, 3) >>> x * 2 ③ Fraction(2, 3) >>> fractions.Fraction(6, 4) ④ Fraction(3, 2) >>> fractions.Fraction(0, 0) ⑤ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "fractions.py", line 96, in __new__ raise ZeroDivisionError('Fraction(%s, 0)' % numerator) ZeroDivisionError: Fraction(0, 0)
fractions
模块。Fraction
对象,并将分子和分母作为参数传递进去。Fraction
对象。2 * (1/3) = (2/3)
Fraction
对象会自动约简分数。(6/4) = (3/2)
您还可以在 Python 中进行基本的三角函数运算。
>>> import math >>> math.pi ① 3.1415926535897931 >>> math.sin(math.pi / 2) ② 1.0 >>> math.tan(math.pi / 4) ③ 0.99999999999999989
math
模块有一个常量,用于表示 π,即圆周与其直径之比。math
模块包含所有基本的三角函数,包括 sin()
、cos()
、tan()
,以及 asin()
等变体。tan(π / 4)
应该返回 1.0
,而不是 0.99999999999999989
。您可以在布尔上下文中使用数字,例如 if
语句。零值是假,非零值是真。
>>> def is_it_true(anything): ① ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(1) ② yes, it's true >>> is_it_true(-1) yes, it's true >>> is_it_true(0) no, it's false >>> is_it_true(0.1) ③ yes, it's true >>> is_it_true(0.0) no, it's false >>> import fractions >>> is_it_true(fractions.Fraction(1, 2)) ④ yes, it's true >>> is_it_true(fractions.Fraction(0, 1)) no, it's false
0.0
为假。注意这一点!如果存在轻微的舍入误差(并非不可能,如上一节所示),那么 Python 将测试 0.0000000000001
而不是 0,并将返回 True
。Fraction(0, n)
对于所有 n 值都是假的。所有其他分数都是真的。⁂
列表是 Python 的主力数据类型。当我提到“列表”时,您可能在想“我必须预先声明大小的数组,它只能包含相同类型的项目,等等”。别这么想。列表比这酷多了。
☞Python 中的列表就像 Perl 5 中的数组。在 Perl 5 中,存储数组的变量总是以
@
字符开头;在 Python 中,变量可以命名为任何东西,Python 会在内部跟踪数据类型。
☞Python 中的列表远不止 Java 中的数组(尽管如果这就是您生活中真正想要的全部,它可以被用作数组)。一个更好的类比是
ArrayList
类,它可以保存任意对象,并且可以在添加新项目时动态扩展。
创建列表很简单:使用方括号括住用逗号分隔的值列表即可。
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] ① >>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[0] ② 'a' >>> a_list[4] ③ 'example' >>> a_list[-1] ④ 'example' >>> a_list[-3] ⑤ 'mpilgrim'
a_list[0]
。a_list[4]
,因为列表始终是零基的。a_list[-1]
。a_list[-n] == a_list[len(a_list) - n]
。因此,在这个列表中,a_list[-3] == a_list[5 - 3] == a_list[2]
。定义好列表之后,您就可以获取列表中的任何部分作为新列表。这被称为对列表切片。
>>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[1:3] ① ['b', 'mpilgrim'] >>> a_list[1:-1] ② ['b', 'mpilgrim', 'z'] >>> a_list[0:3] ③ ['a', 'b', 'mpilgrim'] >>> a_list[:3] ④ ['a', 'b', 'mpilgrim'] >>> a_list[3:] ⑤ ['z', 'example'] >>> a_list[:] ⑥ ['a', 'b', 'mpilgrim', 'z', 'example']
a_list[1]
)开始,一直到但不包括第二个切片索引(在本例中为 a_list[3]
)。a_list[0:3]
返回列表的前三个项目,从 a_list[0]
开始,一直到但不包括 a_list[3]
。a_list[:3]
与 a_list[0:3]
相同,因为起始 0 是隐式的。a_list[3:]
与 a_list[3:5]
相同,因为此列表有五个项目。这里有一个令人愉快的对称性。在这个包含五个项目的列表中,a_list[:3]
返回前 3 个项目,而 a_list[3:]
返回最后两个项目。实际上,a_list[:n]
始终返回前 n 个项目,而 a_list[n:]
返回其余项目,而不管列表的长度如何。a_list[:]
是创建列表完整副本的简写形式。有四种方法可以向列表中添加项目。
>>> a_list = ['a'] >>> a_list = a_list + [2.0, 3] ① >>> a_list ② ['a', 2.0, 3] >>> a_list.append(True) ③ >>> a_list ['a', 2.0, 3, True] >>> a_list.extend(['four', 'Ω']) ④ >>> a_list ['a', 2.0, 3, True, 'four', 'Ω'] >>> a_list.insert(0, 'Ω') ⑤ >>> a_list ['Ω', 'a', 2.0, 3, True, 'four', 'Ω']
+
运算符连接列表以创建新列表。列表可以包含任意数量的项目;没有大小限制(除了可用内存)。但是,如果内存是一个问题,您应该注意列表连接会在内存中创建第二个列表。在这种情况下,该新列表会立即分配给现有的变量 a_list。因此,这一行代码实际上是一个两步过程——连接然后分配——当您处理大型列表时,这可能会(暂时)消耗大量内存。append()
方法将单个项目添加到列表的末尾。(现在列表中有*四个*不同的数据类型!)extend()
方法接受一个参数(一个列表),并将该参数的每个项目追加到原始列表中。insert()
方法将单个项目插入列表中。第一个参数是列表中将被从位置中剔除的第一个项目的索引。列表项目不需要是唯一的;例如,现在有两个具有值 'Ω'
的独立项目:第一个项目 a_list[0]
和最后一个项目 a_list[6]
。☞
a_list.insert(0, value)
类似于 Perl 中的unshift()
函数。它将一个项目添加到列表的开头,并且所有其他项目的位置索引都会向上移动以腾出空间。
让我们更仔细地看一下 append()
和 extend()
之间的区别。
>>> a_list = ['a', 'b', 'c'] >>> a_list.extend(['d', 'e', 'f']) ① >>> a_list ['a', 'b', 'c', 'd', 'e', 'f'] >>> len(a_list) ② 6 >>> a_list[-1] 'f' >>> a_list.append(['g', 'h', 'i']) ③ >>> a_list ['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']] >>> len(a_list) ④ 7 >>> a_list[-1] ['g', 'h', 'i']
extend()
方法接受一个参数,该参数始终是列表,并将该列表的每个项目添加到 a_list 中。append()
方法接受一个参数,该参数可以是任何数据类型。这里,您正在使用包含三个项目的列表调用 append()
方法。>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list.count('new') ① 2 >>> 'new' in a_list ② True >>> 'c' in a_list False >>> a_list.index('mpilgrim') ③ 3 >>> a_list.index('new') ④ 2 >>> a_list.index('c') ⑤ Traceback (innermost last): File "<interactive input>", line 1, in ? ValueError: list.index(x): x not in list
count()
方法返回列表中特定值的出现次数。in
运算符比使用 count()
方法略快。in
运算符始终返回 True
或 False
;它不会告诉您该值在列表中出现的次数。in
运算符和 count()
方法都不会告诉您值出现在列表中的位置。如果您需要了解值在列表中的位置,请调用 index()
方法。默认情况下,它将搜索整个列表,尽管您可以指定可选的第二个参数(从 0 开始的)索引来开始搜索,甚至可以指定可选的第三个参数(从 0 开始的)索引来停止搜索。index()
方法找到列表中值的第一个出现位置。在本例中,'new'
在列表中出现两次,在 a_list[2]
和 a_list[4]
中,但 index()
方法只会返回第一个出现位置的索引。index()
方法将引发异常。等等,什么?没错:如果在列表中找不到该值,index()
方法将引发异常。这与大多数语言显着不同,大多数语言会返回一些无效索引(如 -1
)。虽然这在一开始似乎很烦人,但我认为您会逐渐喜欢它。这意味着您的程序将在问题的源头崩溃,而不是稍后以奇怪且无声的方式失败。请记住,-1
是有效的列表索引。如果 index()
方法返回 -1
,那么这可能会导致一些不太有趣的调试会话!
列表可以自动扩展和收缩。您已经看到了扩展部分。还有几种不同的方法可以从列表中删除项目。
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list[1] 'b' >>> del a_list[1] ① >>> a_list ['a', 'new', 'mpilgrim', 'new'] >>> a_list[1] ② 'new'
del
语句从列表中删除特定项目。1
后访问索引 1
不会导致错误。所有被删除项目之后的项目都会将它们的位置索引移至“填充”删除项目后创建的“间隙”。不知道位置索引?不用担心;您可以按值而不是按位置删除项目。
>>> a_list.remove('new') ① >>> a_list ['a', 'mpilgrim', 'new'] >>> a_list.remove('new') ② >>> a_list ['a', 'mpilgrim'] >>> a_list.remove('new') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.remove(x): x not in list
remove()
方法从列表中删除项目。remove()
方法接受一个值,并从列表中删除该值的第一个出现位置。同样,所有被删除项目之后的项目都会将它们的位置索引向下移动以“填充”间隙。列表永远不会有间隙。remove()
方法,但如果您尝试删除不在列表中的值,它将引发异常。另一个有趣的列表方法是 pop()
。pop()
方法是另一种从列表中删除项目的方法,但带有一个小技巧。
>>> a_list = ['a', 'b', 'new', 'mpilgrim'] >>> a_list.pop() ① 'mpilgrim' >>> a_list ['a', 'b', 'new'] >>> a_list.pop(1) ② 'b' >>> a_list ['a', 'new'] >>> a_list.pop() 'new' >>> a_list.pop() 'a' >>> a_list.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: pop from empty list
pop()
列表方法将删除列表中的最后一个项目,并返回它删除的值。pop()
方法。它将删除该项目,将所有位于其后的项目移至“填充”间隙,并返回它删除的值。pop()
将引发异常。☞不带参数调用
pop()
列表方法类似于 Perl 中的pop()
函数。它从列表中删除最后一个项目,并返回已删除项目的 value。Perl 还有另一个函数shift()
,它删除第一个项目并返回其值;在 Python 中,这等效于a_list.pop(0)
。
您也可以在布尔上下文中使用列表,例如 if
语句。
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true([]) ① no, it's false >>> is_it_true(['a']) ② yes, it's true >>> is_it_true([False]) ③ yes, it's true
⁂
一个 元组 是一个不可变的列表。元组一旦创建,就不能以任何方式更改。
>>> a_tuple = ("a", "b", "mpilgrim", "z", "example") ① >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple[0] ② 'a' >>> a_tuple[-1] ③ 'example' >>> a_tuple[1:3] ④ ('b', 'mpilgrim')
a_tuple[0]
。元组和列表之间最主要的区别是,元组不能更改。在技术术语中,元组是 不可变的。在实践术语中,它们没有允许您更改它们的方法。列表具有 append()
、extend()
、insert()
、remove()
和 pop()
等方法。元组没有任何这些方法。您可以切片元组(因为这会创建一个新的元组),并且可以检查元组是否包含特定值(因为这不会更改元组),并且……就是这样。
# continued from the previous example >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple.append("new") ① Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'append' >>> a_tuple.remove("z") ② Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'remove' >>> a_tuple.index("example") ③ 4 >>> "z" in a_tuple ④ True
append()
或 extend()
方法。remove()
或 pop()
方法。in
运算符来检查元组中是否存在元素。那么元组有什么用呢?
assert
语句,它表明此数据是常量,并且需要特殊考虑(以及特定函数)才能覆盖它。☞元组可以转换为列表,反之亦然。内置的
tuple()
函数接受一个列表,并返回一个包含相同元素的元组,而list()
函数接受一个元组,并返回一个列表。实际上,tuple()
会冻结一个列表,而list()
会解冻一个元组。
您可以在布尔上下文中使用元组,例如 if
语句。
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(()) ① no, it's false >>> is_it_true(('a', 'b')) ② yes, it's true >>> is_it_true((False,)) ③ yes, it's true >>> type((False)) ④ <class 'bool'> >>> type((False,)) <class 'tuple'>
这是一个很酷的编程快捷方式:在 Python 中,您可以使用元组一次分配多个值。
>>> v = ('a', 2, True)
>>> (x, y, z) = v ①
>>> x
'a'
>>> y
2
>>> z
True
(x, y, z)
是一个包含三个变量的元组。将一个分配给另一个会按顺序将 v 的每个值分配给每个变量。这有各种用途。假设您想为一系列值分配名称。您可以使用内置的 range()
函数与多变量赋值一起快速分配连续值。
>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ① >>> MONDAY ② 0 >>> TUESDAY 1 >>> SUNDAY 6
range()
函数构建一个整数序列。(从技术上讲,range()
函数返回一个迭代器,而不是列表或元组,但您将在后面了解这种区别。)MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY和SUNDAY是您定义的变量。(此示例来自calendar
模块,这是一个有趣的小模块,它打印日历,就像UNIX程序cal
一样。calendar
模块为一周中的每一天定义整型常量。)1
,依此类推。您还可以使用多变量赋值来构建返回多个值的函数,只需返回包含所有值的元组即可。调用者可以将其视为单个元组,也可以将这些值分配给单个变量。许多标准 Python 库都这样做,包括os
模块,您将在下一章中了解到。
⁂
一个集合是无序的“袋子”,包含唯一的值。单个集合可以包含任何不可变数据类型的元素。一旦您有两个集合,您就可以进行标准的集合运算,如并集、交集和集合差。
首先要做的就是创建集合。这很容易。
>>> a_set = {1} ① >>> a_set {1} >>> type(a_set) ② <class 'set'> >>> a_set = {1, 2} ③ >>> a_set {1, 2}
{}
) 中。您还可以从一个列表中创建一个集合。
>>> a_list = ['a', 'b', 'mpilgrim', True, False, 42] >>> a_set = set(a_list) ① >>> a_set ② {'a', False, 'b', True, 'mpilgrim', 42} >>> a_list ③ ['a', 'b', 'mpilgrim', True, False, 42]
set()
函数。(知道集合如何实现的迂腐的人会指出,这实际上并不是调用函数,而是实例化一个类。我保证您将在本书的后面了解到这两者的区别。现在,只需知道set()
的行为像函数一样,它返回一个集合。)还没有值?没关系。您可以创建一个空集合。
>>> a_set = set() ① >>> a_set ② set() >>> type(a_set) ③ <class 'set'> >>> len(a_set) ④ 0 >>> not_sure = {} ⑤ >>> type(not_sure) <class 'dict'>
set()
。{}
吗?这将表示一个空字典,而不是一个空集合。您将在本章后面的内容中了解字典。有两种不同的方法可以向现有集合添加元素:add()
方法和update()
方法。
>>> a_set = {1, 2} >>> a_set.add(4) ① >>> a_set {1, 2, 4} >>> len(a_set) ② 3 >>> a_set.add(1) ③ >>> a_set {1, 2, 4} >>> len(a_set) ④ 3
add()
方法接受一个参数,该参数可以是任何数据类型,并将给定值添加到集合中。>>> a_set = {1, 2, 3} >>> a_set {1, 2, 3} >>> a_set.update({2, 4, 6}) ① >>> a_set ② {1, 2, 3, 4, 6} >>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) ③ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 13} >>> a_set.update([10, 20, 30]) ④ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}
update()
方法接受一个参数(一个集合),并将所有成员添加到原始集合中。这就像您对集合中的每个成员都调用了add()
方法一样。update()
方法。当用两个集合调用时,update()
方法会将每个集合的所有成员添加到原始集合中(删除重复元素)。update()
方法可以接受多种不同数据类型的对象,包括列表。当用列表调用时,update()
方法会将列表的所有项添加到原始集合中。有三种方法可以从集合中删除单个值。前两种方法,discard()
和remove()
,之间有一个细微的差别。
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set {1, 3, 36, 6, 10, 45, 15, 21, 28} >>> a_set.discard(10) ① >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.discard(10) ② >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.remove(21) ③ >>> a_set {1, 3, 36, 6, 45, 15, 28} >>> a_set.remove(21) ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 21
discard()
方法接受一个值作为参数,并将该值从集合中删除。discard()
方法,它不会执行任何操作。不会报错;它只是一个无操作。remove()
方法也接受一个值作为参数,它也会从集合中删除该值。remove()
方法会引发KeyError
异常。与列表一样,集合也有pop()
方法。
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set.pop() ① 1 >>> a_set.pop() 3 >>> a_set.pop() 36 >>> a_set {6, 10, 45, 15, 21, 28} >>> a_set.clear() ② >>> a_set set() >>> a_set.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'pop from an empty set'
pop()
方法从集合中删除一个值并返回该值。但是,由于集合是无序的,因此集合中没有“最后一个”值,因此无法控制删除哪个值。它是完全任意的。clear()
方法会从集合中删除所有值,只剩下一个空集合。这等效于a_set = set()
,它将创建一个新的空集合并覆盖a_set变量的先前值。KeyError
异常。Python 的set
类型支持几种常见的集合运算。
>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} >>> 30 in a_set ① True >>> 31 in a_set False >>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} >>> a_set.union(b_set) ② {1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127} >>> a_set.intersection(b_set) ③ {9, 2, 12, 5, 21} >>> a_set.difference(b_set) ④ {195, 4, 76, 51, 30, 127} >>> a_set.symmetric_difference(b_set) ⑤ {1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}
in
运算符。这与列表的工作原理相同。union()
方法返回一个新的集合,其中包含任一集合中的所有元素。intersection()
方法返回一个新的集合,其中包含两个集合中都存在的元素。difference()
方法返回一个新的集合,其中包含存在于a_set中但不存在于b_set中的所有元素。symmetric_difference()
方法返回一个新的集合,其中包含存在于两个集合中的一个集合中的所有元素。这三种方法都是对称的。
# continued from the previous example >>> b_set.symmetric_difference(a_set) ① {3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127} >>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) ② True >>> b_set.union(a_set) == a_set.union(b_set) ③ True >>> b_set.intersection(a_set) == a_set.intersection(b_set) ④ True >>> b_set.difference(a_set) == a_set.difference(b_set) ⑤ False
最后,您还可以向集合提出一些问题。
>>> a_set = {1, 2, 3} >>> b_set = {1, 2, 3, 4} >>> a_set.issubset(b_set) ① True >>> b_set.issuperset(a_set) ② True >>> a_set.add(5) ③ >>> a_set.issubset(b_set) False >>> b_set.issuperset(a_set) False
False
。您可以在布尔上下文中使用集合,例如在if
语句中。
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(set()) ① no, it's false >>> is_it_true({'a'}) ② yes, it's true >>> is_it_true({False}) ③ yes, it's true
⁂
一个字典是一个无序的键值对集合。当您向字典添加一个键时,您还必须为该键添加一个值。(您随时可以更改该值。)Python 字典经过优化,以便在您知道键的情况下检索值,反之则不行。
☞Python 中的字典类似于 Perl 5 中的哈希。在 Perl 5 中,存储哈希的变量总是以
%
字符开头。在 Python 中,变量可以命名为任何东西,Python 在内部跟踪数据类型。
创建字典很容易。语法类似于集合,但您没有值,而是键值对。一旦您有了字典,您就可以按键查找值。
>>> a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'} ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['server'] ② 'db.diveintopython3.org' >>> a_dict['database'] ③ 'mysql' >>> a_dict['db.diveintopython3.org'] ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'db.diveintopython3.org'
'server'
是一个键,它关联的值(由a_dict['server']
引用)是'db.diveintopython3.org'
。'database'
是一个键,它关联的值(由a_dict['database']
引用)是'mysql'
。a_dict['server']
是'db.diveintopython3.org'
,但a_dict['db.diveintopython3.org']
会引发异常,因为'db.diveintopython3.org'
不是键。字典没有预定义的大小限制。您可以随时向字典添加新的键值对,也可以修改现有键的值。从前面的示例继续
>>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['database'] = 'blog' ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'blog'} >>> a_dict['user'] = 'mark' ② >>> a_dict ③ {'server': 'db.diveintopython3.org', 'user': 'mark', 'database': 'blog'} >>> a_dict['user'] = 'dora' ④ >>> a_dict {'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'} >>> a_dict['User'] = 'mark' ⑤ >>> a_dict {'User': 'mark', 'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}
'user'
,值'mark'
)似乎位于中间。事实上,这些项在第一个示例中似乎按顺序排列只是一个巧合;它们现在似乎不再按顺序排列也是一个巧合。user
键的值改回 "mark" 吗?不会!仔细观察该键 — 那是"User"中的大写U。字典键区分大小写,因此该语句正在创建一个新的键值对,而不是覆盖现有键值对。它可能看起来很像,但就 Python 而言,它完全不同。字典不仅仅用于字符串。字典值可以是任何数据类型,包括整数、布尔值、任意对象,甚至其他字典。在一个字典中,这些值并不需要全部是同一类型;您可以根据需要进行混合匹配。字典键的限制更多,但可以是字符串、整数以及其他几种类型。您也可以在一个字典中混合匹配键数据类型。
事实上,您已经在您的第一个 Python 程序中看到了包含非字符串键和值的字典。
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
让我们在交互式 shell 中将其拆解。
>>> SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], ... 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']} >>> len(SUFFIXES) ① 2 >>> 1000 in SUFFIXES ② True >>> SUFFIXES[1000] ③ ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] >>> SUFFIXES[1024] ④ ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] >>> SUFFIXES[1000][3] ⑤ 'TB'
len()
函数会告诉您字典中键的数量。1000
**是** `SUFFIXES` 字典中的一个键;它的值是一个包含八个元素的列表(确切地说,是八个字符串)。1024
是 `SUFFIXES` 字典中的一个键;它的值也是一个包含八个元素的列表。您也可以在 布尔上下文中 使用字典,例如 `if` 语句。
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true({}) ① no, it's false >>> is_it_true({'a': 1}) ② yes, it's true
⁂
无
None
是 Python 中的一个特殊常量。它是一个 空 值。None
与 False
不同。None
不是 0。None
不是空字符串。将 None
与除 None
以外的任何内容进行比较,始终会返回 False
。
None
是唯一的空值。它有自己的数据类型 (NoneType
)。您可以将 None
分配给任何变量,但不能创建其他 NoneType
对象。所有值为 None
的变量都彼此相等。
>>> type(None) <class 'NoneType'> >>> None == False False >>> None == 0 False >>> None == '' False >>> None == None True >>> x = None >>> x == None True >>> y = None >>> x == y True
在 布尔上下文中,None
为假,而 not None
为真。
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(None) no, it's false >>> is_it_true(not None) yes, it's true
⁂
fractions
模块math
模块© 2001–11 马克·皮尔格里姆