Python Tutorial(五):数据结构
这章将更加详细的描述你已经学过的东西,并添加一些新的内容。
5.1 更多有关列表
列表数据类型有更多的方法,下面是列表对象的所有方法:
list.append(x),在列表的末尾添加一项,等同于a[len(a):] = [x]。
list.extend(L),通过追加给定列表的所有项来扩展列表,等同于a[len(a):] = L。
list.insert(i, x),在指定的位置插入一项。第一个参数是将要在它前面进行插入的元素的索引,所以a.insert(0, x)在列表的最前端插入,并且a.insert(len(a), x)等同于a.append(x)。
list.remove(x),移除列表里面第一个值为x的项。如果列表里面没有这个项将报错。
list.pop([i]),移除列表里面指定位置的项,并返回它。如果没有指定索引,a.pop()移除并返回列表里面的最后一项。(在方法签名里面i用方括号包围表示参数是可选的,并不是你应该在那个位置输入方括号。)
list.index(x),返回列表里面第一个值为x的项的索引。如果列表里面没有这个项将报错。
list.count(x),返回列表里面x出现的次数。
list.sort(),按位置排序列表里面的所有项。
list.reverse(),按位置反转列表里面的所有项。
一个示例使用了列表的大多数方法:
你或许已经注意到了像insert,remove或sort这些修改列表的方法并没有返回值被打印出来,它们返回None。对于Python里面所有的可修改的数据结构这是一个设计原则。
5.1.1 列表用作栈
列表的方法可以比较容易的把列表作栈来使用,最后一个元素添加的地方正是第一个元素获得的地方(后进先出)。在栈的顶端添加一项,使用append()方法。在栈的顶端获得一项,使用pop()方法并且不用指定参数。例如:
5.1.2 列表用作队列
也可以把列表当作一个队列来使用,第一个元素添加的地方正是第一个元素获得的地方(先进先出);对于这个目的列表不是很有效。从列表的末尾追加和弹出非常快,在列表的开头进行插入和弹出是很慢的(因为所有其它的元素都需要移动一个位置)。
实现一个队列,使用collections.deque,它被设计为从两端追加和弹出都非常快。例如:
5.1.3 列表的理解
列表理解提供一个简洁的方式来创建列表。普通的应用将创建一个新列表,它的每一个元素都是一些操作应用于另一个序列或可迭代对象的每一个成员的结果,或者创建一个那些元素的满足一个确定条件的子序列。
例如,假定我们想创建一个平方的列表,像:
我们可以获得同样的结果:
这同样也等同于squares = list(map(lambda x: x**2, range(10))),但是更加简洁和可读。
一个列表的理解是由一个包含后跟for从句的表达式,然后是零个或多个for或if从句的方括号组成的。结果是一个新的列表,源于在这个表达式后面的for或if从句的上下文中来计算这个表达式。例如,这个listcomp将连接两个列表的元素如果它们不相等的话:
它等同于:
注意for和if语句的顺序在这些代码片段中是如何一样的。
如果表达式是一个元组(例如上一个示例中的(x, y)),它必须被括住:
列表的理解可以包含复杂的表达式和嵌套的函数:
5.1.4 嵌套列表的理解
一个列表理解里面的初始化表达式可以是任意表达式,包含另一个列表的理解。
考虑下面这个3x4矩阵的示例实现为一个元素为3个长度为4的列表的列表:
下面的列表理解将转置所有的行和列:
就像我们在上一节中所看到的,嵌套的listcomp在它后面的for语句的上下文中被计算,所以这个示例等同于:
按顺序,和下面的一样:
在现实世界中,你应该优先选择内建函数而不是复杂的语句流。对于这种用法zip()函数将做一大部分工作:
5.2 del语句
有一种方式使用元素的索引而不是元素的值从列表里面移除一项:del语句。这和带有返回值的pop()方法不同。del语句也可以用于从列表里面移除切片或清空整个列表(稍早前我们的做法是给一个切片赋一个空列表)。例如:
del也可以用于删除整个变量:
在这以后再引用名称a将报错(至少直到另一个值赋给它)。我们稍后将发现del的其它用法。
5.3 元组和序列
我们看到列表和字符串有许多共同的属性,像索引和切片操作。它们是序列数据类型的两个例子。因为Python是一个正在进化的语言,其它序列数据类型也可以被加进来。也有另一个标准的序列数据类型:元组。
一个元组由一些逗号分割的值组成,例如:
就像你看到的那样,在输出元组的时候总是用圆括号括住,所以嵌套的元组也可以被正确解释;在输入的时候可以有或没有圆括号包围,虽然通常不管怎样圆括号是必须的(如果元组是一个大的表达式的一部分)。不可能对一个元组的单个项进行赋值,然而可以创建一个包含可变对象的元组,就像列表。
虽然元组看起来像列表,它们通常用于不同的情况和不同的目的。元组是不可改变的,通常包含一个复杂序列的元素通过解压缩或索引来进行访问。列表时可改变的,它的元素通常是同类的并且通过在列表上进行迭代来访问。
一个特别的问题是包含零个或一个项的元组的创建:要适应它的话语法有一些极其奇怪。空的元组由一对空的圆括号组成;有一个项的元组由后面带逗号的值组成(用圆括号括住一个单一的值是不够的)。看上去很丑,但很有效。例如:
语句t = 12345, 54321, 'hello!'是一个元组压缩的例子;值12345,54321和'hello!'被一起压缩到一个元组里。相反的操作也是可以的:
这被叫做序列解压缩是足够合适的并对右边的序列起作用。序列解压缩要求等号左边的变量数目和右边的序列元素数目相等。注意多元赋值就是元组压缩和序列解压缩的结合。
5.4 集合
Python也包含集合数据类型。集合是一个无序,不重复的数据集。基本的应用包括成员关系测试和去除重复实体。集合对象同样支持数学运算,像并集,交集,差集和对称差集。
花括号或set()函数可以用来创建集合。注意,创建一个空的集合必须使用set(),而不是{}。后者是用来创建空字典的,我们在下一节讨论这个数据结构。
这是一个简单的演示:
和列表的理解相似,集合的理解也支持:
5.5 字典
另一个Python内建的有用的数据类型是字典。字典在其它语言里通常叫做关联存储或关联数组。不像序列,它是通过一系列数字来索引的。字典是通过键值来索引的,可以是任何不可变的类型。字符串和数字都可以作为键。元组也可以用作键如果它只包含字符串,数字或元组。如果一个元组直接或间接的包含了可变对象,它不可以再作为键。你不可以使用列表作为键,因为列表可以使用索引按位置赋值,切片赋值,或像append()和extend()方法。
最好把字典认为成一个无序的键值对集合。要求是在一个字典里面的所有键都必须是唯一的。一对花括号创建一个空的字典。放入一个逗号分割的键值对列表就是初始化了这个字典,这就是字典输出的方式。
字典的主要操作就是使用键来存储或获取值。也可以使用del表达式来删除键值对。如果你使用了一个已经存在的键进行存储时,那么这个键所关联的旧值将会被覆盖。如果使用一个不存在的键来获取值的话会产生一个错误。
在一个字典上执行list(d.keys())返回一个所有键的列表,任意顺序(如果你希望排序的话,使用sorted(d.keys()))。检查一个键是否在字典里,使用in关键字。
这是一个使用字典的小例子:
dict()构造函数直接从序列的键值对构建字典:
另外,字典的理解可以从任何的键值表达式创建字典:
当键是简单的字符串时,使用关键字参数来指定键值对有时候更加容易:
5.6 循环技术
当循环字典时,键和对应的值可以使用items()方法同时或得到:
当循环序列时,位置索引和对应的值可以使用enumerate()函数同时获得:
同时循环两个或更多的序列时,可以使用zip()函数进行项的配对:
当以逆序循环一个序列时,首先指定序列为向前的方向,然后调用reversed()函数:
当以一定的顺序循环一个序列时,使用sorted()函数,它返回一个新的已排序的列表,而不修改原来的:
想要在循环里面改变你正在迭代的序列(例如重复某个确定的项),强烈建议你先做一个拷贝。循环一个序列并不隐式的做一个拷贝。切片的记法使这个变得尤其方便:
5.7 更多有关条件
while和if表达式的条件可以包含任何操作符,不仅仅是比较。
比较操作符in和not in检查一个值是否在序列里面。操作符is和is not比较两个对象是否是同一个对象,这只是对于可变对象,如列表的事情。所有的比较操作符有相同的优先级,低于所有的数字操作符。
比较可以被链接在一起。例如a < b == c测试a是否小于b,此外b是否等于c。
比较可以使用布尔操作符and和or结合起来,比较的结果(或任何其它的布尔表达式)可以使用not取反。这些操作符的优先级低于比较操作符,在它们之间,not有最高的优先级,or最低,所以A and not B or C 和(A and (not B)) or C相等。括号总是可以用来表达期望的组合。
布尔操作符and和or就是被叫做的所谓的短路操作符,它们的参数是从左到右计算。当结果可以确定时,计算立马就会停止。例如,如果A和C是true,但是B是false,A and B and C将不计算表达式C。当用于一般的值而不是布尔值,短路操作符的返回值是最后一个计算的参数。
可以把比较和其它布尔表达式的值赋给变量。例如:
注意,在Python里不像C那样,赋值不能出现在表达式里面。C程序员可能会抱怨,它为了避免在C程序里遇到的一个普通类别的问题,当你需要相等符号==时却输入了赋值符号=。
5.8 序列和其它类型的比较
同样类型的序列可以比较。比较使用词典里的顺序。首先使用第一对元素进行比较,如果不同的话就可以决定比较的结果了。如果相同,就比较第二对元素,等等,直到任何一个序列的元素使用完。如果被比较的两个元素它们本身又是相同类型的序列,按字典顺序比较被递归的进行。如果所有的元素都相等,序列就被认为是相等的。如果一个序列是另一个序列起始位置的子序列,短的序列是较小的那个。词典顺序对于字符串来说使用Unicode编码点数字来排序单个字符。一些相同类型的序列比较示例:
注意,使用<和>比较不同类型的对象是合法的,只要对象能够提供合适的比较方法。例如,混合数字类型通过它们的数字值来比较,索引0等于0.0。否则,而不是提供一个任意的排序,解释器将产生一个类型错误异常。
本文是对官方网站内容的翻译,原文地址:http://docs.python.org/3/tutorial/datastructures.html