本章我们将学习如何使用Python的组合数据类型将数据项集合在一起,以便在程序设计时有更多的选项。
组合数据类型
1、序列类型
Python提供了5中内置的序列类型:bytearray、bytes、list、str与tuple,序列类型支持成员关系操作符(in)、大小计算函数(len())、分片([]),并且是可可迭代的。
1.1 元组
元组是个有序序列,包含0个或多个对象引用,使用小括号包裹。元组是固定的,不能替换或删除其中包含的任意数据项。
1.1.1 元组的创建
使用()创建一个元组:
括号内不包含内容,则创建一个空元组
括号内包含使用逗号分隔的数据项,创建一个非空元组
也可以使用tuple()创建一个元组:
不指定参数时,返回一个空元组
使用tuple作为参数时,返回该参数的浅拷贝
其他参数时,尝试将给定的对象转换为tuple类型
1.1.2 元组索引和分片
1.1.3 元组方法
元组只提供两种方法:
1.1.4 元组运算符
与字符串一样,元组之间可以使用 + 号和 * 号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。
1.1.5 元组的删除
元组中的元素值是不允许删除的,但我们可以使用del删除整个元组:
1.1.6 无关闭分隔符
当元组出现在二进制操作符的左边或出现在unary语句的右边时,可以不使用圆括号。
1.2 命名的元组
命名的元组(namedtuple)与普通元组一样,有相同的表现特征,其添加的功能就是可以根据名称引用元组中的项。
collections模块提供了namedtuple()函数,用于创建自定义的元组数据类型。该函数的第一个参数是想要创建的自定义元组数据类型的名称,第二个参数是一个字符串,其中包含使用空格分隔的名称,每个名称代表该元祖数据类型中的一项。该函数返回一个自定义的类,可用于创建命名的元组。
这里我们创建了包含两个Sale项的列表,我们可以使用索引位置来引用元组中的项,也可以使用名称进行引用,后者正式命名的元组的特点:
1.3 列表
列表是包含0个或多个对象引用的有序序列,支持与字符串以及元组一样的分片与步距语法,列表是可变的,因此我们可以对列表中的项进行删除或替换,插入、替换或删除列表中的分片也是可能的。
1.3.1 列表的创建
使用[]创建一个元组:
括号内不包含内容,则创建一个空列表
括号内包含使用逗号分隔的数据项,创建一个非空列表
也可以使用list()创建一个列表:
不指定参数时,返回一个空列表
使用list作为参数时,返回该参数的浅拷贝
其他参数时,尝试将给定的对象转换为list类型
1.3.2 列表索引和分片
1.3.3 列表方法
下表中,L为列表。
1.3.4 拆分操作符
任意可迭代的(列表、元组等)数据类型都可以使用序列拆分操作符进行拆分,即*。用于赋值操作符左边的两个或多个变量时,其中一个使用*进行引导,数据项将赋值给该变量,而所有剩下的数据项将给带星号的变量。
1.3.5 删除
由于列表是可变的,我们可以对其数据项进行删除。
删除单个数据项
删除分片
1.3.6 列表内涵
列表内涵是一个表达式,也是一个循环,该循环有一个可选的、包含在方括号中的条件,作用是为列表生成数据项,并且可以使用条件过滤掉不需要的数据项,可以使用表达式,也可以使用附加条件。常见语法:
[expression for item in iterable]
[expression for item in iterable if condition]
在没有列表内涵时,我们找出1900~1940年之间所有的闰年,可能会这么写:
学习了列表内涵之后我们可以简化程序:
两种方法等效,得到同样的结果。
2、集合类型
set也是一种组合数据类型,支持成员关系操作符(in)、对象大小计算操作符(len()),并且也是iterable。Python提供了两种内置的集合类型:可变的set类型,固定的frozenset类型。进行迭代时,集合类型以任意顺序提供其数据项。
只有可哈希运算的对象可以添加到集合中。所有的内置固定数据类型(比如float、frozenset、int、str、tuple)都是可哈希运算的,可以添加到集合中。内置的可变数据类型(比如dict、list、set)都不是可哈希运算的,不能添加到集合中。
2.1 集合
集合是0个或多个对象引用的无序组合。集合是可变的,因此可以很容易的添加和移除数据项,但是由于其中的项是无序的,因此没有索引位置的概念,也不能分片或按步距分片。
2.1.1 集合的创建
使用set()创建一个集合:
不指定参数时,返回一个空集合
使用set作为参数时,返回该参数的浅拷贝
其他参数时,尝试将给定的对象转换为集合
集合中包含的每个数据项都是独一无二的——添加重复的数据项固然不会引发问题,但是也毫无意义。比如,下面产生的三个集合是一样的:set('apple')、set('aple')、{‘e', 'p', 'l', 'a'}。鉴于此,集合常用于删除重复的数据项。比如,x是一个字符串列表,在执行之后,x中的每个字符串都是独一无二的,存放顺序是任意的。
2.1.2 集合方法与操作符
s、t为集合,x为数据项。
2.1.3 集合内涵
除了调用set()创建集合,或使用集合字面值创建集合外,我们可以使用集合内涵创建集合。集合内涵是一个表达式,也是一个带有可选条件的循环,支持的语法:
2.2 固定集合
固定集合是指那种一旦创建就不能修改的集合,只能使用frozenset数据类型函数创建,不带参数调用时,frozenset()返回一个空的固定集合,带一个frozenset参数时,将返回改参数的 浅拷贝,对于任何其他类型的参数,都尝试将给定的对象转换为一个forzenset。
3、映射类型
映射是键-值数据项的组合,并提供了存取数据项及其键、值的方法。Python3.0支持两种无序的映射类型——内置的dict类型以及标准库中的collections.defaultdict类型。Python3.1引入了一种新的、有序的映射类型collections.OrderedDict,该类型是一个字典,与内置的dict有相同的方法和属性,但在存储数据项时以插入顺序进行。
3.1 字典
dict是一种无序的组合数据类型,其中包含0个或多个键-值对。
3.1.1 字典的创建
可以使用{}创建:
空的花括号创建一个空的字典
包含一个或多个逗号分隔的键值对,创建一个非空字典
也可以使用dict()函数创建:
不带参数,创建一个空的字典
带有dict类型的参数,返回该参数的浅拷贝
键值对组合的参数,创建非空字典
字典的键值是独一无二的,因此,如果向字典中添加一个已存在的键值项,实际效果是新值替换旧值。
3.1.2 字典方法
d为字典
上面提到了“视图”概念,其相对于通常的iterables有两个不同点:
如果该视图引用的字典发生变化,那么视图将反映该变化。
键视图与项视图支持一些类似于集合的操作:
v & x # Intersection
v | x # Union
v - x # Difference
v ^ x # Symmentric difference
注:两种通过键取值方式的比较
我们可以通过d[k]和d.get()两种形式来取值,比如我们进行词频统计时,使用words[word]+=1或words[word] = words.get(word, 0) + 1都可以进行加1操作,但是如果单词第一次出现,第一种形式会产生KeyValue错误,第二种则会正确运行。
3.1.3 字典内涵
字典内涵是一个表达式,也是一个循环,该循环带有一个可选条件。语法:
例:
3.2 默认字典
默认字典也是一种字典——这种字典包含普通字典所提供的所有操作符与方法,与其不同的是可以对遗失的键进行处理。
创建默认字典时,我们可以传入一个工厂函数,这样就会为遗失的键创建默认值。看下面例子
上面我们创建的默认字典words永远不会产生KeyError异常,如果遇到没有的键,其值通过工厂函数(int())设置为0。
3.3 有序字典
有序字典collections.OrderedDict是以数据项的插入顺序进行存储。
可以看出我们通过二元组列表创建有序字典后,获取去键视图也为有序的。
有序字典另一种稍专业一些的用途是生成排序字典。给定一个字典d,可以按如下方式转换为排序字典:。
4、组合数据类型的迭代与复制
4.1 迭代子、迭代操作与函数
iterable数据类型每次返回其中的一个数据项。任意包含__iter__() 方法的对象或任意序列(也即包含__getitem__()方法的对象)都是一个iterable,并可以提供一个迭代子。迭代子是一个对象,该对象可以提供__next__()方法,该方法依次返回每个相继的数据项,并在没有数据项时产生StopIteration异常。
常见的迭代操作符与函数(s与t为序列):
数据项返回的顺序依赖于底层的iterable。对列表和元组等情况,数据项的返回值通常从第一个数据项开始依次返回,而对于字典与集合,迭代子是任意顺序的返回项。
4.2 组合类型的复制
由于数据片总是曲子某个数据项的一个单独副本,所以获取一个列表的副本可以通过下面方式:
对于字典和集合,可以使用dict.copy()和set.copy()来实现。此外,copy模块还提供了copy.copy()函数,该函数返回给定对象的一个副本。
在以上各种组合数据类型创建的时候,提到可以使用工厂方法来创建一个组合数据类型的副本:
注意:以上的复制都是浅拷贝,也就是说,复制的知识对象引用而非对象本身。对于固定数据类型(数字、字符串等),这与复制的效果是相同的,但对于可变的数据类型,比如嵌套的组合类型,这意味着相关对象同时被原来的组合与复制得来的组合引用。请看下面代码:
从输出结果可以看出,前两项固定数据类型并没有同时改变,而列表中的列表同时变化,说明x与y的第三项都指向的同一列表的引用。我们可以使用深拷贝来避免此类问题:
从输出结果看,x与y已经完全独立了。
领取专属 10元无门槛券
私享最新 技术干货