容器
Python中,可包含其他对象的对象,称之为“容器”。容器是一种数据结构。
常用的容器主要划分为两种:序列(如:列表、元祖等)和映射(如:字典)。序列中,每个元素都有下标,它们是有序的。映射中,每个元素都有名称(又称“ 键 ”),它们是无序的。
除了序列和映射之外,还有一种需要注意的容器——“ 集合 ”。
通用的序列操作
有 5 种操作是所有序列中通用的。
索引
所谓“索引”,就是在序列中,根据所需元素的下标,返回所需元素。
我们可以直接在字符串上索引。直接在我们的目标序列后面加个索引所需的中括号就可以了。不仅如此,我们还可以在input函数上对用户输入的内容直接索引。
切片
切片,就是在序列中切一块。
序列相加
其实就是用“+”来拼接序列。
乘法
其实就是用“*”来进行乘法运算。
成员资格
所谓“成员资格”测试,就是指“用运算符 in 来检测指定元素是否包含于序列”。
例如:
如果元素包含于序列,程序返回“True”;反之,返回“False”。
列表
现在来总结下列表相比于其他序列特殊的地方——“可修改”与“列表方法”。
开始之前应提到函数 list。
该函数对任何序列都有用。
(1)、修改列表
1、给元素赋值
直接利用下标就可以修改列表(明显的用户友好型)。
2、用 del 函数删除
其实 del 函数对很多东西都适用。
3、用切片替换
切片的作用的实际情况就是用一个片段替换另一个片段。
用空列表来操作的话,我们就可以达到和删除一样的效果。
以及和增加一样的效果。
(2)、列表方法
所谓方法,就是指与对象(字符串,参数等)紧密联系的函数。
方法调用时,方法前要加上对象名和句点。
1、append
append函数会将指定对象直接加到列表末尾。
注——养成良好编程习惯:
在实际运用中,为了不使计算机发生识别障碍,一般不提倡使用和函数名一样的变量名。所以之前所举的例子中,使用“ list ”命名变量实际是一个错误的示范(与 list 函数同名)。
2、clear
像字面意思一样,一键归零。
实际效果可以用另一句话代替。
3、copy
和字面意思一样,复制。
当然,它也是可替代的。
实际上,这函数意义不大,因为根本没必要这么麻烦。
直接赋值就行了。
4、count
计数的,看你出现了几次。
5、extend
append 的增强版,可以把一段加到列表后面。
同样可以被代替,一个简单的加号就可以完成。
切片也可以做到,但代码可读性相对不高。
6、index
在列表中依次(下标从小到大)查找元素,若元素存在,则返回第一次出现的下标。反之,若元素不存在,则返回错误。
7、insert
按你所提供的下标插入你所提供的元素。(前为下标,,后为元素)
8、pop
从列表中依据你所提供的下标删除对应元素,并返回所删除的元素。当pop函数括号中不含下标时,默认为列表最后一个元素。
若括号中含有下标,则按括号中来进行。删除后的列表将不含删除值。
注:
pop函数是唯一一个既修改了列表又返回了函数值的函数。(注意“修改了”的前提,copy函数便没有修改,也含有返回值。)
如图:
list1在接受了函数append的返回值后,直接变成了None,这是因为append函数直接返回了None。你可能会发现这里我用了print函数,而没有像之前一样用语句直接返回。这是因为对空的list1,只有用print才有返回值,用语句直接输入无返回值。
而pop函数有返回值。
push 和 pop是大家普遍接受的两种“栈”操作。Python不提供 push ,所以我们用 append 来代替。
9、remove
remove会删除列表中含有的第一个用户指定的元素。
10、reverse
将列表倒过来。
你会发现这些函数全都可以用切片来实现。
11、sort
将列表按从小到打的顺序排序,无返回值。
这里要提到一个类似的函数——sorted。
sorted 有返回值,故可以直接赋值。
sorted 函数适用于所有序列,但它永远返回一个列表。
12、高级排序
sort 函数可以接受两个关键字参数——key 和 reverse。
key 会给每一个元素生成一个相应的键,再按根据生成的键来进行排序。
那么,key 是以什么为参考来设置键的呢?这依赖于我们给它所赋予的函数。
我们知道函数 len 是返回每个元素的长度,而“ key = len ”,就是我们前面所提到的将函数赋予 key 。这里,len 函数将每个元素的长度返回,key 参数接收了这些长度值并转化为键,sort 函数接受了键并进行排序,最终得到我们的结果。
与 key 相同的是,reverse 参数也需要赋值。但我们不能赋予其函数,而只能赋予其布尔值。reverse 将根据布尔值来决定函数排序后的反向排列是否执行。
元组
元组也是序列,只是不能修改。语法也简单,加个逗号就可以变元祖。圆括号反倒无关紧要。
逗号至关重要!
有无逗号就是计算机识别是否为元组的依据。
元组并不复杂,对它的操作也不多。除了不可修改外,与它打交道的方法和对列表打交道的方法没有不同(index、count等元祖没有的方法除外。)
比如切片在列表怎么用,对元组就怎么用。
一般而言,在序列方面的需求,一个列表就足以满足。那么我们接触元组有什么意义吗?
1、元组用作映射中的键。(列表不能)
2、有些内置函数返回元组。(你还有什么理由?)
字符串方法
前面我们谈到了列表的方法,字符串的方法比其多得多。这里我们只讨论其中最有用的方法。当然,笔者以后可能会在这篇文章的基础上,继续补充更多的字符串方法,所以,应该先学好这篇文章的方法再考虑更多的事情。
字符串方法大多是从模块 string 中继承而来,在较早的 python 版本中,这些方法就是模块 string 中的函数。如果有需要,我们至今仍可以引用这个模块。
为什么这个模块至今仍未淘汰?
因为模块 string 包含一些字符串方法里没有的函数与常量。
例如:
string.digits:包含数字0~9的字符串。
string.ascii_letters:包含所有ASCII字母(大写与小写)的字符串。
string.punctuation:包含所有ASCII标点字符的字符串。
…………
当然,虽然说的是ASCII字符,但其实是未解码的Unicode字符串。
(1)、center
运用 center 方法,我们可以在指定字符串的两边填充特殊字符(默认为空格)。
括号里的数字限定了程序输出的字符串的长度。
计算机会先获取输入字符串的位数,与 center 方法里的数值进行比较。如果数值大于位数,那么计算机会将输入字符串居中,多余位置进行指定字符的填充工作。计算机会默认将多余位置左右平均分配,但如果多出来的数是单数,那么计算机会默认把多出来的一位放在右边
如果位数大于或等于数值,那么计算机会直接返回原字符串。
类似方法扩展(再次强调,下面的内容不是重点,请自行选学):
string.ljust(width[,fillchar]):返回一个长度为 max(len(string),width) 的字符串,其开头为当前字符串的副本,末尾为 fillchar 的指定字符(默认为空格)。
string.rjust(widtn[,fillchar]):返回一个长度为 max(len(string),width) 的字符串,其开头为 fillchar 的指定字符(默认为空格),末尾为当前字符串的拷贝。
string.zfill(width):返回一个长度为 width 的字符串,相比原字符串,符号说明符(+、-)移到了开头,字符串的左边已被 0 填充。
(2)、find
我们可以通过 find 方法来检验字符串中是否含有某一子串。若子串存在,则 find 方法会返回该子串第一次出现的位置上的第一个字符的位置,若没有找到,则返回-1。
这就类似于我们之前提到的列表方法 index。
之前讲 index 时没有提到某个细节,在这里和 find 一起提出来。find 和 index 均可以指定遍历的初始索引和终止索引。
三个位置分别代表(“子串”,起始索引,终止索引)。值得注意的是,该方法便利的范围包含起始索引位置,不包含终止索引位置。Python中常有这样的设定。
类似方法扩展:
string.rfind(sub[,start[,end]]):返回遍历到的最后一个子串的最后一个字符的位置的索引,若没有找到,则返回-1,可以指定起始索引和终止索引。
string.index(sub[,start[,end]]):返回遍历到的第一个子串的第一个字符的位置的索引,若没有找到,则返回 ValueError 异常,可以指定起始索引和终止索引。
string.rindex(sub[,start[,end]]):返回遍历到的最后一个子串的最后一个字符的位置的索引,若没有找到,则返回 ValueError 异常,可以指定起始索引和终止索引。
string.count(sub[,start[,end]]):记录 sub 出现的次数,可以指定起始索引和终止索引。
string.startswith(prefix[,start[,end]]):检查字符串是否以 prefix 打头,可以指定检查的起始索引和终止索引。
string.endswith(suffix[,start[,end]]):检查字符串是否以 suffix 结尾,可以指定检查的起始索引和终止索引。
3、join
字如其意,可以合并序列的元素。
值得注意的是:第一,用来合并的序列必须是字符串列表;第二,其实际效果是将原字符串插入字符串列表的空隙中从而形成一个新的字符串。
4、lower
lower 会将字符串内所有的英文字母改为小写形式。
类似方法扩展:
string.islower():检查字符串中所有英文字母是否都为小写。
string.istitle():检查字符串中位于非字母的后面的第一个字母是否为大写,其他字母是否为小写。
string.isupper():检查字符串中的所有英文字母是否都为大写。
string.translate(table):根据转换表 table 对字符串中的所有字符都进行转换,并返回结果。
string.capitalize():返回字符串的副本,但第一个字母大写。
string.casefold():返回经过标准化后的字符串。
string.swapcase():反转字符串中所有字母的大小写,并返回。
string.title():将字符串中位于非字母的后面的第一个字母转换为大写。
string.upper():将字符串中的所有英文字母转换为大写。
词首大写问题:
既然说到 tittle 方法,就不得不谈谈词首大写问题。确实,title 可以将首字母转换为大写。但它的转换结果却有些不合理。
你看,它将空格识别为了非字母的字符,从而导致每个单词都变成了首字母大写。另一种类似的方法是使用 string 模块中的函数 capwords。
那么,可不可以改善这个问题呢?当然可以,但是这得靠你自己改善自己的代码,注意各种标点符号可能导致的结果。
总而言之,靠自己。
5、replace
用 replace 方法将指定字符串替换为另一个字符串,并改变结果。
用不了多久,你就会明白这方法很有用。
类似方法扩展:
string.expandtabs([tabsize]):返回将字符串中的制表符展开为空格后的结果,可指定可选参数 tabsize( 默认为8 ) 。
6、split
split 恰好是 join 的反面,依据目标字段分割指定字段。
如果你没有指定分隔符的话,程序就会默认在单个或多个连续的空白字符(空格、制表符、换行符等)处进行拆分。
类似方法扩展:
string.partition(sep):在字符串中搜索 sep,并会以括号中的方式返回元祖。(sep 前的字段,sep,sep 后的字段)
string.rpartition(sep):功能与上一个相同,但返回的元祖前后相反。
string.split([sep[,maxsplit]]):与 split 功能相同,但方向为从后往前。maxsplit 可以指定最大划分数。
string.splitlines([keepends]):返回一个列表,其中包含字符串的所有行,若参数 keepends 为 true,则将会包含换行符。
7、strip
strip 可用来删除字符串开头和末尾的指定字符,当参数为 None 时,则默认为空格。
类似方法扩展:
string.lstrip([chars]):将字符串开头所有的 chars 都删除,并返回结果。
string.rstrip([chars]):将字符串末尾所有的 chars 都删除,并返回结果。
应用举例:
假设你需要依据学校的数据库来查找亚历山大同学的相关数据,那么你自然需要以他的名字为索引。
但是,你无法确定这位同学在输入自己的名字时所输入的大小写情况。无法明了情况,一个个试的话就会很费力。一个学生还可以试出来,一百个呢?
如何解决这种情况?只需利用 lower 一键变成小写,再搜索 “Alexanda”即可。
同样的,假设亚历山大同学是为标新立异的同学,他在输入自己的名字时,加入了特殊字符来装饰自己的名字,例如“ **$$ Alexanda . Bell $$** ”。
那么这时便可以使用 strip 来消除这位同学的鬼点子,虽然不确定特殊字符具体是哪几个,但我们可以将键盘上的字符全部输入为参数,就可以消除所有特殊字符。当然,若是他引用了Unicode里的特殊字符的话,已经可以暴打一顿了。
8、translate
translate 和 replace 一样可以替换字符串的特定部分,虽然 translate 只可以替换单字符,但由于 translate 可以同时替换多个字符,所以效率要高于 replace 。
为了使用 translate,我们要确立一个转换表 table 。table 将引入两个参数,确立 Unicode 码点间的映射关系,进行转换。
当然我们也可以直接查看 table,不过我们只能看到码点而已。
9、判断字符串是否满足特定的条件
很多以 is 开头的字符串方法都会判断指定的字符串是否满足某些条件,若满足,则执行该方法,反之,则不执行。
字典
字典直接这样创造,前“键”后“值”,合起来称之为“项”。(字典中的“键”必须是独一无二的)
字典是 Python 中的唯一内置映射,和之前所提到的列表、字符串一样,字典也拥有它的转换函数—— dict (其实根本就不是一个函数,而是一个类)。值得注意的是,下图的转换我们利用了元组。
也可以利用关键字实参来调用这个函数。
(1)、字典的基本操作
字典的基本操作与序列非常类似。
len( dict ):返回字典 dict 对应的项数。
d[ k ]:返回与键 k 相应的值。
d[ k ] = v:直接将值 v 关联到键 k 。
del d[ k ]:删除键为 k 的项。
k in d:检查键 k 是否包含于字典 d 。
这里指出一些重要的不同之处。
1、键的类型:与序列的索引不同,字典的键不限于整数,任何不可变的数据类型皆可以为键。
2、自动增加:我们可以直接将字典不含有的项加入字典,而不需像序列一样用取代或函数的方式,这一点之后会说明。
3、成员资格:a in d 是指 a 是否存在于字典 d 的键中,而不是值中。而在序列中,in 用来查找相应的值。
(2)、将字符串格式设置功能用于字典
之前讲过利用字符串格式设置功能来设置值得格式。其实,我们也可以利用利用字典,来使得格式设置更容易。但是在使用字典时,我们必须使用 format_map 来指明对象。
如你所见,通过 format_map 指明对象后,我们可以通过键来同时代入多个对象。不得不提的是,在模板系统中,这种设置方式很有用。
(3)、字典方法
字典方法的使用并没有列表和字符串那样频繁,所以可以在需要时,再来学习这里。
1、clear
和列表中的 clear 一样,可以清除字典中的所有项。这个方法其实是很有用的,我们来看两段代码:
第一段:
第二段:
我承认上述代码对初学者不太友好,这主要有关 python 的数据储存方式,如果你可以明了我在说什么的话,你可以很容易就从上面的代码中明了我想表达 clear 的什么用法。如果看不懂上述代码,可以先忽略上述代码,直接看下一个方法。
2、copy
和列表方法中的 copy 一样,copy执行的是字典的复制。然而这种复制是一种“浅复制”。
和之前一样,如果你明了 python 的数据存储方式,就能看懂上述代码究竟发生了什么。当我们执行浅复制时,如果替换副本中的值,原本不会改变。但若修改副本中的值,则原本会改变。
深复制则不会发生这种问题,如果要实现深复制的话,就必须使用模块 copy 中的函数 deepcopy
3.fromkeys
使用该方法可以创建一个新字典,其中包含指定的键,且每个键对应的值都是 None 。
当然,也可以直接对 dict 调用 fromkeys 。我们之前说过 dict 并非函数,而是类。熟悉了这一点,就很好理解这一操作。
当然,我们也可以指定我们所需要的值。
4、get
如果你试图直接访问字典中不存在的项。
如果你使用 get 来访问项,如果项不存在:
如果项存在
那么他就等价于直接访问字典的结果了。
5、items
items 会返回一个包含所有字典项的列表,其中每个元素都为键值对的形式,且排列顺序不确定。
这种类型称之为“字典视图”,可以用于迭代。我们可以用 len() 确认其长度,以及用 in 对其执行成员资格检查。
字典视图的一个特性就是:它不属于复制,它始终是底层字典的反应,底层字典发生变化,相应的字典视图也会发生变化。
6、keys
返回一个字典视图,但只包含键。
7、pop
同列表中的使用一样,效果也一样。不过 pop 的括号中放入的是键。
8、popitem
类似于 pop 。
由于字典属于映射,各元素之间没有顺序关系,所以 popitem 只是随机剔除一个项。如果想要 popitem 以可预测的顺序弹出项,请参阅模块 collections 中的 OrderedDicts 类。
9、setdefault
类似 get ,可以获取与指定键相关联的值。当字典不包含该项时,则自动加入该项。
10、update
使用另一个字典中的项来更新目标字典。没有的会加入,不同的会替换。
11、values
类似于 keys,返回一个有字典中的值所组成字典视图。