列表与字典
列表
Python列表是:
任意对象的有序集合
从功能上看,列表就是收集其他对象的地方,你可以把它们看做组。同时列表维护了其中每一项从左到右的位置顺序(也就是说,它们是序列)
通过偏移量访问
就像字符串一样,你可以通过列表的对象的偏移量对其进行索引,从而读取对象的一部分内容。由于列表的每一项都是有序的,你也可以执行诸如分片和拼接之类的任务。
可变长度,异构以及任意嵌套
与字符串不同的是,列表可以原位置正常或者缩短(长度可变),并且可以包含任意类型的对象,而不仅仅包含单个字符的字符串(列表和字符串是异构的)。因为列表能够包含其他复杂的对象,又能够支持任意类型的嵌套,因此你可以创建列表的子列表的子列表等。
属于可变序列的分类
就类型分类而言,列表是可变对象,可以在原位置上被修改,也可以响应所有针对字符串的操作序列,例如索引,分片和拼接。实际上,序列操作在列表与字符串中的工作方式相同,唯一的区别就是:但应用于字符串上的拼接和分片这样的操作作用于列表时,返回的是新列表。列表是可变的,因此它们也支持字符串不能支持的其他操作,例如删除和索引赋值操作,它们会在原位置修改列表。
对象引用数组
从技术上来讲,Python列表包含了含有0个或多个其他对象的引用。列表也会让你想起其他语言中的指针(地址)数组,从Python的列表中读取一个项的速度基本上与索引一个C语言的数组差不多。实际上,在标准的Python解释器内部,列表就是C数组而不是链接结构,我们曾在第六章学过,每当你把一个对象赋值给一个数据结构或变量名时,Python总是会存储同一个对象的应用,而不是对象的一个副本(除非你显式地要求保存副本)
表8-1 : 常用列表字面量和操作
操作 解释
L = [] 一个空列表
L = [123,'ABC',1.23,{}] 四项,索引为0到3
L = ['Bob',40.0,['adw','zxc']] 嵌套的子列表
L = list('asdw') 一个可迭代对象元素的列表
L = list(range(-4,4)) 连续整数的列表
L [i] 索引
L [i][j] 索引的索引
L[i:j] 分片
len(L) 求长度
L1 + L2 拼接
L * 3 重复
for x in L:print(x) 迭代
3 in L 成员关系
L.append(4) 尾部添加
L.extend([5,6,7]) 尾部扩展
L,insert(i,X) 插入
L.index(x) 索引
L.count(x) 计数
L.sort() 排序
L.copy() 复制
L.reverse() 反转
L.clear() 清除
L.pop(i) 删除i处元素
L.remove(X) 删除元素X
del L[i] 删除i处元素
del L[i:j] 删除i到j处的片段
L[i:j] = [] 删除i到j处的片段
L[i] = 3 索引赋值
L[i:j] = [4,5,6] 片段赋值
L = [x**2 for x in range(5)] 列表推导和映射
list(map(ord,'asdw'))
列表的实际应用
基本列表操作
由于列表是序列。支持很多和字符串相同的操作、如拼接和重复
尽管列表的拼接"+"操作和字符串中的一样,但是,值得重视的是”+”两边必须是相同类型的序列。
列表推导和迭代
for循环会从左到右遍历任何序列中的项,对于for迭代和range内置函数会在13章正式讨论。
列表推导只不过是通过对序列中的每一项应用一个表达式来构建一个新的列表的方式。
这个表达式功能上等同于手动构建一个结果的列表的for循环,列表推导的编码更简单,而且在今天的Python中似乎运行起来更快。
正如第四章介绍的,内置函数map能实现类似的效果,但它对序列中的各项应用一个函数并把结果收集到一个新的列表中
由于我们还没有准备好完整的姐搜啊迭代,我们将推迟更多细节。
索引,分片和矩阵
由于列表都是序列,对于列表而言,索引和分片操作与字符串中的操作基本相同。然而对列表进行索引结果就是你指定的偏移量处的对象,而列表进行分片时往往会返回一个新的列表:
由于可以在列表中嵌套列表(和其他对象类型),有时需要将几次索引操作连在一起使用来深入到数据结构中去,举个例子,最简单的一个办法是将其表示为矩阵(多维数组)。
原位置修改列表
列表是可变的,支持原位置改变列表对象的操作。不像字符串那样强迫你建立一个新的副本。
索引与分片的赋值
当使用列表时,可以将它赋值给一个特定项(偏移)或整个片段(分片)来改变它的内容。
索引和分片的赋值都是原位置修改,它们对主体列表进行直接修改,而不是时曾有过新的列表作为结果。
即使要替换的部分或替换它的内容为空,分片赋值也是一次性替换整个片段,因为被赋值的序列长度不一定要和被赋值的分片长度相匹配。所以分片赋值能够用来覆盖,插入,删除。
Python中还有更加简单的方法实现这些,如inseter,pop,remove。
列表方法调用
与字符串相同,Python列表对象也支持特定类型方法调用,其中很多调用可以在原位置修改主体。
方法就是附属并作用于特定对象的函数。
最常用的可能是append,它能够简单的将一个单项(对象引用)加至列表末端。与拼接不同的是,append允许传入的单一对象而不是列表。append与拼接+的结果类似,但是拼接产生新的对象,而append原位置修改。
更多关于列表排序
另一个更常见的方法是sort,它原位置对列表进行排序,sort使用了Python标准的比较检验作为默认检验,而且默认采用递增的顺序进行排序,可以通过传入关键词参数对sort的行为进行修改。在排序函数中,reverse参数允许排序以降序而不是升序进行,key参数给出了一个单个参数的函数,它返回在排序中使用的值。
排序的key参数可以通过索引每个字典挑选出一个排序键。
这里需要主要,append和sort虽然原位置修改,但是结果没有返回值,返回值皆为None,如果向上面这样编写b = a.sort(),b不会得到任何结果,如果是a = a.sort,那么你反而会失去整个列表的引用。
如果你想要得到返回结果,可以使用sorted,
其他常见列表方法
reverse可以原位置反转列表,extend和pop方法分别能够在末端插入多个元素,删除一个元素,也有一个reversed内置函数,像sorted一样工作并返回一个新的结果对象
从技术上来讲,extend方法总是循环访问可迭代对象,并逐个把产生的元素添加到列表尾部,然而append会字节把和这个传入可迭代对象添加到尾部而不会遍历它。
在某些类型的应用程序中,往往会把这里用到的列表pop方法和append方法连用,以实现楷书的后进先出栈结构,列表末端作为栈的顶端。
pop方法也能够接受一个每一个即将被删除并返回元素的偏移量,默认值为最后一个元素的偏移量,也就是-1.其他列表方法可以通过值删除remove某元素,在偏移量处插入insert某元素,计算某元素的出现次数,查找某元素的偏移量等。
其他常见列表操作
用于列表是可变的,你可以使用del语法在原位置删除某项或某片段。
分片赋值是删除外加插入操作,你可以通过将空列表赋值给分片来删除列表片段,
如果将空列表赋值给一个缩影,则会在指定的位置存储空列表对象的引用,而不是删除该位置上的元素。
字典
除了列表之外,字典也许是Python中最灵活的内置函数结构类型。如果把列表看做有序对象的集合,那么就可以吧字典当作无序的集合。它们主要的差别在于:字典中的元素是通过键来存取的,而不是通过偏移量。字典能够扮演记录,搜索表,以及其他任何元素的键比索引重要的数据结构。
字典的主要属性如下:
通过键而不是偏移量来读取
字典有所又被叫做关联数组或散列表。它们通过键将一系列值联系起来,
任意对象的无序集合
保存在字典中的项没有特定的顺序,Python将各项伪随机从左到有随机排序,以便快速查找。键提供了字典中项的象征性位置。
长度可变,异构,任意嵌套
字典可以在原位置上增长或缩短,可以包含任何类型的对象,而且他们指出任意深度的嵌套,每个键只有一个与之相互关联的值,但是这个值可以是一系列多个所需对象的几个,而一个值也可以同时存储在多个键下
属于可变映射类型
通过给索引赋值,字典可以在原位置修改,字典是可变的,字典不是序列,是无序集合,字典是唯一内置,核心映射类型。也就是把键映射到值的对象,Python中的其他需要通过导入模块来创建。
对象引用表(散列表)
字典是作为散列表实现的,一开始很小,并根据要求而增长,此外,Python采用优化过的散列算法来寻找键,因此搜索速度很快。中的存储的是对象的引用。
表8-2 常见字典字面量和操作
D = {} 空字典
D = {'name':'YB',‘age‘:23} 有两个元素的字典
D = {'ASDW': {'name':'YB',‘age‘:23} } 嵌套
D = dict(name = 'YB',age=23) 其他构造方法:关键字
D = dict([('name','YB),('age',23)]) 键值对
D = dict(zip(keyslist,valslist)) 拉链式键值对
D = dict.formkeys(['a','b']) 键列表
D['name'] 通过键索引
D['ASDW']['name'] 嵌套索引
‘’age‘’ in D 成员关系,键存在测试
D.keys() 方法,所有键
D.values() 所有值
D.item() 所有键值对
D.copy() 顶层复制
D.dlear() 删除
D.update(D2) 通过键合并
D.get(key,default?) 通过键获取,如果不存在默认返回None
D.pop(key,default?) 通过键删除,如果不存在返回错误
D.setdefauult(key,default?) 通过键获取,如果不存在默认返回None
D.popitem() 删除/返回所有的键值对
len(D) 长度,键值对数
D[key] = 42 新增,修改,删除键
del D [key] 根据键删除条目
list(D.keys()) 查看字典键
D1.key()&D2.key()
D = {x:x**2 for x in range(10)} 字典推导
字典的实际应用
字典通过键进行索引,嵌套字典项是由一系列索引来访问的,当Python创建字典时,会按照任意所选从左到右的顺序来存储项。为了取回一个值,你需要提供相应的键
字典的基本操作
通常情况下,创建字典并且通过键离开存储,访问其中的项
使用方括号语法,用键对字典进行索引操作,只不过这里意味着用键来读取,而不是用位置,字典不是顺序结构。
这里长度计算的是键值对数目,而in成员关系判断也是根据键名,而不是值,
在Python3.X中keys返回的是一个可迭代对象,而不是我们常见的结构。
原位置修改字典
字典时可变的,所以可以在原位置上修改它,而不需要生成新的字典,只需要给一个键赋值就可以改变或生成新的元素,del语句在这里也适用。在Python中,所有集合数据类型都可以彼此任意嵌套。
与列表相同,像字典中任何已存在的键赋值都会改变与之索引相关联的值,当对新的键赋值会产生新的键值对。
嵌套字典方法
字典也用很多属于自己的方法,例如values(),items()。和keys一样返回可迭代对象,所以需要放在list中使用比较好,以便一次性收集它们所有的值用于显示。
在那些运行时收集数据的实际程序中,通常不能在执行前预计将出现在一个字典中的数据。读取不存在的键往往汇报材料,通过get方法访问不存在的键会返回默认值None。
字典的update方法类似于拼接,但是和顺序无关,再次强调,字典不是顺序结构,它将一个字典的键值拼接到另一个字典中,遇到键值冲突时盲目的覆盖相同的键和值。
字典不使用加法拼接操作,总是会用新的值覆盖旧的值。
字典的pop方法能够从字典中删除一个键并返回它的值,类似于列表的pop方法,只不过删除的是一个键而不是一个可选的位置
如果这个键不存在会报错。字典也提供copy方法,它是避免相同字典共享引用潜在的副作用的一种方式。
字典用法的一些注意事项
序列运算无效
字典是映射机制,不是序列,没有顺序的概念
对新索引赋值会添加项
当编写字典字面量时或单独向现有字典对象的新键赋值时,都会生成键,最终结果是相同的
键不一定总是字符串
任何不可变对象都可以作为键。
用字典模拟灵活的列表:整数键
这里看起来像是一个有100项的序列,但这其实是一个有单个元素的字典
或许可以用来当做年份表
这里将值替换成一些有趣的东西可以用来存储真正有意义的数据
对稀疏数据结构使用字典:用元组做键
类似的,字典也常常用于实现稀疏数据结构,例如,对于那些只有少数位置上有存储值的多维数组
这里我们用字典表示一个三维数组,只有(2,3,4)和(7,8,9)位置上有值,其他位置都为空。
避免不存在的操作
读取不存在的键这样的操作在稀疏矩阵中很常见,这里有三种方法可以避免报错
就编码角度,get方法是最简洁的。不过if和try语句往往更加简洁
字典的嵌套
Python的数据集合都能够任意嵌套
创建字典的其他方式
这四种形式后悔建立相同的两键字典,但是它们有着不同的使用条件
如果你可以事先拼出整个字典,第一种是方便的
如果你需要一次动态的建立字典的一个字段,第二种比较合适
第三种关键字形式需要的代码比字面量少,但键必须是字符串
如果你需要在程序运行时通过序列结构创建字典,那么最后一种比较适用。
最后一种形式通常也会与zip函数一起使用,把程序运行时动态获取的单独键列表和单独的值列表一一拼接在一起。
字典VS列表
字典和列表都是能够灵活管理其他对象的集合工具,但是列表将元素赋值给位置,而字典却将元素赋值给更加便于记忆的键,因此,字典数据通常为人类读者提供更多的信息。
对于一些数据类型而言,列表的按位置访问是有意义的,例如一个公司中员工的列表,一个目录中的文件,或者数据矩阵。但是像这样一个更加符号化的记录也许能更有意义的编写为一个字典,使用带标签的字段来代替字段位置。
在实际应用中,字典使用于存储带有标签的数据,以及需要通过名称直接查询的结果,而非缓慢的线性搜索。
我们也可以使用集合,它更像是没有键的字典,它们不会把键映射到值,但是通常可以像字典一样快速查找元素,尤其在搜索程序中。
留意:字典接口
字典不只是一种在程序中,通过键值对存储信息的方便方式,一些python的扩展工具也提供了从外观到实现上都与字典一样的接口,例如,Python像DB,的键访问文件暴露在接口就很像一个需要被打开的字典,你使用键索引存储并访问字符串
第二十八章你也可以使用这种方法存储以整个Python对象,对于网络访问,Python的CGI脚本也支持提供了一个字典一样的接口。
尽管字典是唯一的核心映射类型,所以这些其他的扩展都是映射的实例,同时支持大多数相同的操作,一旦你学会字典接口,你将会发现他们适用于一系列Python的内置工具。
本章小结
本章中我们探讨了列表和字典的类型,这可能是在Python程序中所见到并使用的两种最常见,最具有灵活性且功能最为强大的集合类型。本章介绍的列表类型支持任意对象以位置排序的集合体而且可以任意嵌套,按照需要增长或缩短,字典类型也是如此,不过它是以键来存储元素而不是位置,并且不会保存元素之间的顺序。列表和字典都是可变的,使用支持各种不适用于字符串的原位置修改操作。
自己总结一下
这一章是列表和字典,很常见,所以感觉没有什么东西,但其实其中的内容都是很重要的,我总结起来很容易,有了整体的框架。都是可变的,原位置修改很重要,列表按顺序,是序列,可以切片,字典是映射,靠键值对,没有什么顺序。
背诵并默写本章习题
本章习题
1,列举两种方法创建内含5个整数0的列表。
像[0,0,0,0,0]这样的字面量表达式以及[0]*5这种重复表达式,都能创建5个0的列表,在实际应用中,你可能会通过循环创建这种列表。一开始是空列表,在每次迭代中通过L.append(0)附加0,这里也可以使用列表推导[0 for i in range(5)]
2.列举两种方式来创建一个字典,有两个键'a'和'b',而每个键相关联的值都是0.
像{'a':0,'b':0}这种字面量表达式,或者像D,D['a'] = 0,D['b'] = 0这种一系列的赋值运算,都会创建所需要的字典。也可以太贵哦编写关键字形式dict(a=0,b=0),或者更灵活的dict([('a',0),('b',0)])键/值序列的形式,因为所有的键值都相同,也可以使用特殊形式dict.fromkeys('ab',0)。还可以使用字典推导,{k:0 for l in 'ab'}
3.列举出四种在原位置修改列表对象的运算
append和extend方法可以在原位置增长列表,sort和reverse方法可以对列表进行排序或者翻转,insert方法可以在偏移量处插入一个元素,remove和pop方法会按照值和位置从列表中删除元素,del语句会生成一个元素或一段切片,而索引以及切片翻转语句则会取代一个元素或整个片段。
4.列举出四种在原位置修改字典对象的运算
字典的修改主要是给新的键或者已存在的键赋值,从而建立或修改键在表中的项目,此外,del会删除一个键的元素,字典update方法会把一个字典合并到另一个字典的适当地方,而D.pop(key)则会移除一个键并返回它的值,字典也有其他更古怪的方法可以在原位置修改,但在这一章没有列出,如setdefault。
5.为什么在一些情况下你要使用字典而不是列表?
如果数据带有标签的话,字典通常是更好的选择(例如带有字段名的一条记录),列表最适合无标签项目的集合(例如一个目录中的文件)。字典查找通常也比列表中的搜索更快,不过这可能会随着不同的程序而变化。