龙空技术网

Python中的容器

编程珠玑 412

前言:

现时咱们对“python 容器”可能比较关怀,我们都需要分析一些“python 容器”的相关知识。那么小编在网络上收集了一些有关“python 容器””的相关知识,希望同学们能喜欢,大家快快来了解一下吧!

一、容器

Python中,可包含其他对象的对象,称之为“容器”。容器是一种数据结构。

常用的容器主要划分为两种:序列(如:列表、元祖等)和映射(如:字典)。序列中,每个元素都有下标,它们是有序的。映射中,每个元素都有名称(又称“ 键 ”),它们是无序的。

除了序列和映射之外,还有一种需要注意的容器——“ 集合 ”。

二、通用的序列操作

有 5 种操作是所有序列中通用的。

(1)、索引

所谓“索引”,就是在序列中,根据所需元素的下标,返回所需元素。

以字符串的索引为例:

‘ 2 ’为第三个元素的下标。当然,为了节省时间,我们大可不必为了索引而引入一个变量。我们可以直接在字符串上索引。

直接在我们的目标序列后面加个索引所需的中括号就可以了。

不仅如此,我们还可以在input函数上对用户输入的内容直接索引。

(2)、切片

切片,就是在序列中切一块。

索引就是拿我们想要的那一个,切片就是切我们想要的那一块。索引只能拿一个,切片可以切一段。其实本质上就是一种东西,切片就是索引的加强版。

两个或三个索引就是切片。而且我们在上面所说的情况,也适用。

特别的,若第二个索引在第一个索引之前,则输出空序列。

若用户填入空索引,计算机将根据前两个索引所处的前后位置,默认为序列的前后端点。

魔兽玩家的浪漫

第三个索引有关“步长”,步长不能为“0”,否则程序无法向前移动。当步长为负数时,切片从后向前执行。

(3)、序列相加

其实就是用“+”来拼接序列。例如:

只不过相加的前提是两者必须为同一类型的序列:

(4)、乘法

其实就是用“*”来进行乘法运算。

(5)、成员资格

所谓“成员资格”测试,就是指“用运算符 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、有些内置函数返回元组。(你还有什么理由?)

五、字符串

本来不想写字符串的,但写序列要是漏了字符串,感觉上还是少了什么。

既然要写,就尽量把基础写全吧。字符串的内容本来就多。接下来的版块将多于列表和元组。

前面我们已经讲过序列的基本操作方法,所以如何使用索引和切片来操作字符串应该不是什么难点。和元祖相同的一点是,字符串不能修改,所以切片赋值和元素赋值等方法都是违法的。当然,我们可以通过其他方法来达到与删减同样的效果。

有关字符串,首先我们来谈谈如何设置字符串的格式。

值得注意的是,对新手而言,这方面的内容起不到多大的实际作用。因为Python编程新手平时用不到这方面的知识,不过这是进阶的必经之路,所以什么时候学习,以及现在是否学习应该先想好,以免浪费时间。

1、设置字符串的格式

设置字符串格式的内容包含很多,这里也只是介绍其主要内容。在接下来的小节中,我们的主要思想是利用 format 函数来替换“替换字段”。

替换字段主要由三部分构成:字段名、转换标志、格式说明符。接下来我们会详细说明相关内容。

(1)、替换字段名

字段名,就是指相应字段的名号(索引和标识符)。利用 format 函数来替换相应字段的字段名,就是我们这一小节的主要目的。

在此之前,我们先来了解一下 format 函数的功能。

format 函数会用括号里的内容替换字符串内花括号内的内容。

当然,多个替换也是可以进行的。当我们不设置指定顺序时,计算机会按默认位置进行替换。

我们可以用数字来指定替换的位置(从0起步)。

也可以利用关键字参数。

当然,用户并非只能访问值得本身,还可以访问值的成分。

也可以使用句点表示法来访问导入的模块中的方法、属性、变量和函数。

(2)、基本转换

根据我们提供的“转换标志”,利用 format 函数可以将目的字段转换为我们想要的格式。

当我们用来转换的字段为字符串时,一般我们会在目的字段与转换标志之间夹入“!”。

如图,这里花括号内的 python 即为目的字段,format 函数括号内的 python 即为我们指定的字符串,而!后的“a、s、r”就是我们所提到的转换标志。

计算机会先用 format 函数括号内的内容代替花括号里的内容,再根据转换标志转换替换后的数据。

这里的 s、r、a、分别表示 str、repr、ascii。了解了这个信息,那么 idle 的返回值就很好理解了。

此外,当我们用来转换的字段为数值时,一般我们会在目的字段与转换标志之间夹入":"。

这里的 b 表示将字段转换为二进制。

当然,还有许多其他的转换标志:c(unicode)、d(十进制)、e(科学表示法)、E(同 e ,但 E 用来表示指数)、f(定点数)……

这里便不一一指出了。

(3)宽度、精度、千位分隔符

某些时候,我们在返回一个值时,需要调节返回值的宽度,以便对齐。所谓的调节宽度,其实就是通过在返回值的前面或后面加空格来调节返回值的位置。

这时,若替换字段为数值,则默认在返回值前面加空格;若替换字段为字符串,则默认在返回值后面加空格。

这里的 20 指的就是所加空格的数量,而空格的数量直接调节了宽度。总结即为:在冒号后面直接加数值来调节宽度。

设置浮点数时,计算机一般默认精确到小数点后六位。但是我们可以根据需要调节我们指定数的精度(精确度)。

这里的“.”表示精度调节,“3”表示精度调节到,“.3”表示精度调节到小数点后3位。

当然,其他类型也可指定精度。

值得注意的是,如果要调节精度与宽度,那么就不能像之前一样用“!”分隔目的字段与指示符,而必须用“:”。

当然,我们也可以同时使用宽度调节、精度调节、转换标志。

要注意必要的格式,宽度调节在最前,精度调节在其后,转换标志在最后,特别提出,这里的 f 表示定点数的转换。

另外一个值得注意的是“千位分隔符”。

当我们在冒号后面加逗号时,则计算机识别我们需要使用千位分隔符。千位分隔符,顾名思义,就是每个三个数位分隔一次。

我们可以同时使用之前所提到的知识。

千位分隔符会放在宽度调节与表示精度调节的句点之间。

(4)、符号、对齐和用 0 填充

有三种方法可以使你输出负数。

第一种,直接在 format 函数后的括号内加负数。

第二种,运用符号说明符。符号说明符往往放在冒号与宽度之间。特别的,如果用空格代替符号说明符,则默认在数值前填充空格。

第三种,直接在字符串内加符号。

很多需要设置数字格式的机制(例如打印一份表格)在大多数情况下只需设置相应的宽度与精度即可。但是在有些时候,我们需要特殊的操作才能实现我们的目的。例如当对象中含有字符串与数值时,由于字符串与数值的默认对齐方式不同(字符串会在前面填充空格,数值会在后面填充空格),往往将引发一系列问题。

为了解决这些问题,我们只需在特定的位置增加一些符号就行了。例如,若在冒号与宽度之间加个“0”,则表示用“0”来填充数值前的空隙。这可以很好的解决当负数存在时,数据长度参差不齐的问题。

若在冒号与宽度之间加入“<、>、=”,则表示“左对齐、右对齐、居中间”,方便数据的一体化操作。

当然,我们还可以用指定字符来代替默认的空格,只需在冒号与宽度间加入指定字符。(注意,特殊字符“$”后加了“^”)

特别的一种情况,如果我们在冒号与宽度之间加入“=”,那么程序的输出值就会将符号说明符与数值远远隔开(实质:默认将符号放在最前面)。

最后我们要提到的一个要素是“#”符号,你可以将其放入符号说明符和宽度之间。(没有符号说明符的话,就是冒号与宽度之间)根据你的数据类型不同,“#”将引发不同的数据转化方式。下面以二进制和十进制为例,在不同的情况下加入“#”,所产生的效果也不同。前者为直接在数值前加入进制类型的表示符,后者为精确到小数点后几位。

下面来谈谈字符串方法。

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 码点间的映射关系,进行转换。

例如,假设我们要将一段英语文本改成带有德国口音的版本,那么我们有必要将所有的“c”,“s”转换成“k”,“z”。

当然我们也可以直接查看 table,不过我们只能看到码点而已。

9、判断字符串是否满足特定的条件

很多以 is 开头的字符串方法都会判断指定的字符串是否满足某些条件,若满足,则执行该方法,反之,则不执行。

例如:string.isalnum、string.isalpha、string.isdecimal、string.isdigit、isspace……

这里便不一一指出,有需要可以自行上网搜索。

接下来,我们开始聊聊字典。

六、字典

字典直接这样创造,前“键”后“值”,合起来称之为“项”。(字典中的“键”必须是独一无二的)

字典是 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 用来查找相应的值。

这里我们要详细说明一下第二点。

通过程序运行我们可以看到,我们无法直接在列表中加入一个新的元素。但是对于字典,我们可以直接加入一个新的项。

如果我要使得我对列表 list1 的操作可行,我就不得不在列表 list1 中加入51个 None 。

(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 对其执行成员资格检查。

字典视图的一个特性就是:它不属于复制,它始终是底层字典的反应,底层字典发生变化,相应的字典视图也会发生变化。

当然,我们可以之间将字典视图用 list 转化为列表进行复制。

6、keys

返回一个字典视图,但只包含键。

7、pop

同列表中的使用一样,效果也一样。不过 pop 的括号中放入的是键。

8、popitem

类似于 pop 。

由于字典属于映射,各元素之间没有顺序关系,所以 popitem 只是随机剔除一个项。如果想要 popitem 以可预测的顺序弹出项,请参阅模块 collections 中的 OrderedDicts 类。

9、setdefault

类似 get ,可以获取与指定键相关联的值。当字典不包含该项时,则自动加入该项。

10、update

使用另一个字典中的项来更新目标字典。没有的会加入,不同的会替换。

11、values

类似于 keys,返回一个有字典中的值所组成字典视图。

以上。

标签: #python 容器