当前位置: 首页 ‣ 深入 Python 3 ‣
难度级别: ♦♦♢♢♢
❝ Wonder is the foundation of all philosophy, inquiry its progress, ignorance its end. ❞
— Michel de Montaigne
让我们暂时将 第一份 Python 程序 抛在脑后,来聊一聊数据类型。在 Python 中, 每个值都有一种数据类型,但您并不需要声明变量的数据类型。那该方式是如何运作的呢?Python 根据每个变量的初始赋值情况分析其类型,并在内部对其进行跟踪。
Python 有多种内置数据类型。以下是比较重要的一些:
True[真]
或为 False[假]
。1
和 2
)、Floats[浮点数](1.1
和 1.2
)、Fractions[分数](1/2
和 2/3
);甚至是 Complex Number[复数]。当然,还有更多的类型。在 Python 中一切均为对象,因此存在像 module[模块]、 function[函数]、 class[类]、 method[方法]、 file[文件] 甚至 compiled code[已编译代码] 这样的类型。您已经见过这样一些例子:模块的 name、 函数的 docstrings
等等。将学到的包括 《类 与 迭代器》 中的 Classes[类],以及 《文件》 中的 Files[文件]。
Strings[字符串]和 Bytes[字节串]比较重要,也相对复杂,足以开辟独立章节予以讲述。让我们先看看其它类型。
⁂
布尔类型或为真或为假。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 同时支持 Integer[整型] 和 Floating Point[浮点型] 数值。无任何类型声明可用于区分;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 的方法进行取整。它是个真正的取整(截断)函数,而不是 floor[地板]函数。☞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
浮点数。//
运算符执行古怪的整数除法。如果结果为正数,可将其视为朝向小数位取整(不是四舍五入),但是要小心这一点。//
运算符将结果朝着最近的整数“向上”四舍五入。从数学角度来说,由于 −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
这样的 布尔类型上下文环境中 使用数值。零值是 false[假],非零值是 true[真]。
>>> 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)
为假。所有其它分数为真。⁂
列表是 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]
返回头三个元素,而 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()
方法只接受一个参数,但可以是任何数据类型。在此,对一个 3 元素列表调用 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
;它不会告诉你该值出现在什么位置。index()
方法。尽管可以通过第二个参数(以 0 为基点的)索引值来指定起点,通过第三个参数(以 0 基点的)索引来指定搜索终点,但缺省情况下它将搜索整个列表,index()
方法将查找某值在列表中的第一次出现。在该情况下,'new'
在列表中出现了两次,分别为 a_list[2]
和 a_list[4]
,但 index()
方法将只返回第一次出现的位置索引值。index()
方法将会引发一个例外。等等,什么?是这样的:如果没有在列表中找到该值, index()
方法将会引发一个例外。这是 Python 语言最显著不同之处,其它多数语言将会返回一些无效的索引值(像是 -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()
方法接受一个 value 参数,并删除列表中该值的第一次出现。同样,被删除元素之后的所有元素将会将索引位置下移,以“填补缝隙”。列表永远不会有“缝隙”。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()
函数。它从列表中删除最后一个元素并返回所删除元素的值。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
模块。
⁂
集合set 是装有独特值的无序“袋子”。一个简单的集合可以包含任何数据类型的值。如果有两个集合,则可以执行像联合、交集以及集合求差等标准集合运算。
重中之重。创建集合非常简单。
>>> 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 的 集合
类型支持几种常见的运算。
>>> 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 中的 hash [散列]类似。在 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" 吗?不会!仔细看看该键——有个大写的 U 出现在 "User" 中。字典键是区分大小写的,因此该语句创建了一组新的键值对,而不是覆盖既有的字典项。对你来说它们可能是一样的,但对于 Python 而言它们是完全不同的。字典并非只能用于字符串。字典的值可以是任何数据类型,包括整数、布尔值、任何对象,甚至是其它的字典。而且就算在同一字典中,所有的值也无须是同一类型,您可根据需要混合匹配。字典的键要严格得多,可以是字符串、整数和其它一些类型。在同一字典中也可混合、匹配使用不同数据类型的键。
实际上,您已经在 your first Python program 见过一个将非字符串用作键的字典了。
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()
函数将返回字典中键的数量。in
运算符以测试某个特定的键是否在字典中。1000
是 字典 SUFFIXES
的一个键;其值为一个 8 元素列表(确切地说,是 8 个字符串)。1024
是字典 SUFFIXES
的键;其值也是一个 8 元素列表。SUFFIXES[1000]
是列表,可以通过它们的 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': 1}) ② yes, it's true
⁂
None
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
在 布尔类型上下文环境中, 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
⁂
© 2001–9 Mark Pilgrim