Python基础手册12——序列(类型操作)

四、序列类型操作符


1、索引和切片操作符 ( [],[:],[::] )

序列类型的元素被顺序放置,这种方式允许通过指定下标的方式来获得某一个数据元素, 或者通过指定下标范围来获得一组序列的元素,这种访问序列单个元素的方式叫做索引,获取子序列的方式叫做切片。

序列支持的索引操作:

sequence[index]
<meta charset="utf-8">

sequence 是序列的名字,index 是想要访问的元素对应的偏移量。偏移量可以是正值,范围从 0 到偏移最大值(比序列长度少1),可以使用内建函数 len() 返回序列的元素个数, 所以:0 <= index <= len(sequece) - 1 。另外,也可以使用负索引,范围是 -1 到序列的负长度:-len(sequence),所以:-len(sequence) <= index <= -1。

正负索引的区别在于正索引以序列的开始为起点,负索引以序列的结束为起点。从技术上讲,一个负偏移与这个字符串的常度相加后得到这个字符串的正的偏移量。我们可以理解为当Python去所以一个负偏移量的时候,会将其负偏移量加上序列的长度后得到对应的正偏移量,再去索引。

试图访问一个越界的索引会引发一个如下的异常:

因为 Python 是面向对象的, 所以你可以像下面这样直接访问一个序列的元素(不用先把它赋值给一个变量):

由于列表、元组中可以包含列表和元组(或其他对象),有时需要将几次索引 操作连在一起使用来深入到数据结构中去。


序列支持的切片操作:

sequence[starting_index:ending_index:step]

当使用一对以冒号分隔的偏移来索引序列类型对象时,我们可以得到从起始索引(starting_index)到结束索引(ending_index)(不包括结束索引对应的元素)之间的所有元素。起始索引和结束索引都是可选的, 如果没有提供或者用 None 作为索引值,其实索引和结束索引会默认为0和分片对象的长度。

对序列对象进行分片操作,会返回一个新的同样类型的对象。

序列的切片操作的第三个索引值(step)被用做步长参数,用作步进,默认为1。我们可以使用负数作为步进参数,这表示Python会从右至左进行分片,而不是通常的从左至右,从而实现序列的反转。

索引和分片的赋值操作都是原处修改,对于不可变对象,会引发错误异常。他们会对可变对象直接进行修改,而不是生成一个新的对象作为结果。

分片赋值时,插入元素的个数不需要与删除的数目相匹配。实际上,分片赋值是一次性替换整个片段或“栏”,因为赋值的序列长度不一定要与被赋值的分片的长度相匹配,所以分片赋值能够用来替换(覆盖)、增长(插入)、缩短(删除)主列表。


2、成员关系操作符 (in, not in)

成员关系操作符使用来判断一个元素是否属于一个序列的。比如对字符串类型来说,就是判断一个字符是否属于这个字符串,对和元组类型来说,就代表了一个对象是否属于该元组。in/not in 操作符的返回值一般来讲就是 True/False,满足成员关系就返回 True,否则返回 False。

obj [not] in sequence


3、连接操作符( + )

这个操作符允许我们把一个序列和另一个相同类型的序列做连接。

sequence1 + sequence2

该表达式的结果是一个包含 sequence1 和 sequence2 的内容的新序列。

注意:这种方式看起来似乎实现了把两个序列内容合并的概念,但是这个操作不是最快或者说最有效的。对字符串来说,这个操作不如把所有的子字符串放到一个列表或可迭代对象中,然后调用一个 join() 方法来把所有的内容连接在一起节约内存。类似地,对列表来说,我们推荐读者用列表类型的 extend() 方法来把两个或者多个列表对象合并。当你需要简单地把两个对象的内容合并, 或者说不能依赖于可变对象的那些没有返回值(实际上它返回一个 None)的内建方法来完成的时候时,连接操作符还是很方便的一个选择。


4、重复操作符 ( * )

当你需要需要一个序列的多份拷贝时,重复操作符非常有用。

sequence * copies_int

copies_int 必须是一个整数,像连接操作符一样,该操作符返回一个新的包含多份原对象拷贝的对象。




五、序列可用的内建函数

在讲解序列类型的内建函数之前,有一点需要说明,序列本身就内含了迭代的概念,之所以会这样,是因为迭代这个概念就是从序列,迭代器,或者其他支持迭代操作的对象中泛化得来的。由于 Python 的 for 循环可以遍历所有的可迭代类型,在(非纯序列对象上)执行 for 循环时就像在一个纯序列对象上执行一样。 而且 Python 的很多原来只支持序列作为参数的内建函数现在也开始支持迭代器或者或类迭代器了。我们把这些类型统称为"可迭代对象"。

1、类型转换函数 list(),tuple() 和 str() (repr())

内建函数 list()str()tuple()[图片上传中...(13.png-ff9688-1515593009797-0)]
被用做在各种序列类型之间转换。这些转换实际上是工厂函数,将对象作为参数,并将其内容(浅)拷贝到新生成的对象中。一旦一个 Python 的对象被建立,我们就不能更改其身份或类型了。如果你把一个列表对象传给 list() 函数,便会创建这个对象的一个浅拷贝,然后将其插入新的列表中。同样地,在做连接操作和重复操作时,我们也会这样处理。

所谓浅拷贝就是只拷贝了对象中元素对象的索引,而不是重新建立了对象中所有的元素对象!如果你想完全的拷贝一个对象(包括递归,如果你的对象是一个包含容器的容器)。你需要用到深拷贝。

list() 和 tuple() 函数在列表类型和元组类型的互换时非常有用。 虽然这些函数也适用于 string 类型(因为 string 类型也是序列的一种),但是在 string 类型上应用 tuple()和 list()函数却得不到我们通常希望的结果。

内建函数 str()repr() 可以获取对象的内容、类型、数值属性等信息的字符串格式。str() 函数得到的字符串可读性好, 而 repr()函数得到的字符串通常可以用来重新获得该对象, 通常情况下 obj == eval(repr(obj)) 这个等式是成立的。这两个函数接受一个对象做为其参数,返回适当的字符串。

尽管 str() 和 repr() 在特性和功能方面都非常相似, 事实上 repr() 返回的是一个对象的“官方”字符串表示, 也就是说绝大多数情况下可以通过求值运算(使用 eval()内建函数)重新得到该对象。但 str()则有所不同,str() 致力于生成一个对象的可读性好的字符串表示,它的返回结果通常无法用于 eval()求值, 但很适合用于 print() 语句输出。

需要再次提醒一下的是, 并不是所有 repr()返回的字符串都能够用eval()内建函数得到原来的对象。

也就是说 repr() 输出对 Python 比较友好, 而 str()的输出对人比较友好。虽然如此,很多情况下这二者的输出仍然都是完全一样的。

2、返回对象的长度 len()

内建函数 len() 可以返回序列对象的长度(元素个数)。


3、返回最大值和最小值 max() 和 min()

对于 string 类型它们能返回最大或者最小的字符(按照ASCII码中的字符的先后顺序比较)。对于元组和列表来说,当其元素都为字符串或者数字对象时,才可以返回正确结果。对于混合对象,结构越复杂返回的结构准确性就越差。




六、拷贝 Python 对象浅拷贝和深拷贝

对象赋值实际上是简单的对象引用。也就是说当你创建一个对象,然后把它赋给另一个变量的时候,Python 并没有拷贝这个对象,而是拷贝了这个对象的引用给变量。

假设你想创建一对小夫妻的通用档案,名为 person。然后你分别为他俩拷贝一份。在下面的例子中,我们展示了两种拷贝对象的方式,一种使用了切片操作,另一种用了工厂方法。为了区分出三个不同的对象,我们使用 id()内建函数来显示每个对象的标识符。(我们还可以用 is 操作符来做相同的事情)

为他们创建了初始有100 的个人存款帐户。用户名改为定制的名字。但是,当丈夫取走 50后,他的行为影响到了他妻子的账户,虽然我们进行了分开的拷贝作(当然,前提是我们希望他们每个人都拥有自己单独的帐号,而不是一个单一的联合帐号)。

原因是我们仅仅做了一个浅拷贝。对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象内容的拷贝(其实都是原对象中元素的引用),换句话说,这个拷贝的对象本身是新的,但是它的内容不是。序列类型对象的浅拷贝是默认类型拷贝,并可以以下几种方式实施:(1)完全切片操作[:],(2)利用工厂函数,比如 list(),dict()等,(3)使用 copy 模块的 copy() 函数。

你的下一个问题可能是:当妻子的名字被赋值,为什么丈夫的名字没有受到影响?难道它们的名字现在不应该都是'jane'了吗?为什么名字没有变成一样的呢?怎么会是这样呢?这是因为在这两个列表的两个对象中,第一个对象是不可变的(是个字符串类型),而第二个是可变的(一个列表)。正因为如此,当进行浅拷贝时,字符串对象和列表对象的引用都被进行拷贝到了新的列表中,正如上图我们看到的,刚拷贝完,person、hubby、wifey三个对象的id不同,但是其内部元素的id都是相同的,正是因为他们内部的元素都指向了相同的对象。而当我们对hubby和wifey第一个元素进行赋值时,由于字符串是不可改变对象,所以他们的第一个元素都指向了各自新创建的字符串对象。由于列表是可变对象。所以hubby对第二个元素列表中的数字进行了修改之后,由于wifey的第二个元素也是指向的同一个列表对象,所以我们看wifey中的钱也发生了变化。

假设我们要给这对夫妻创建一个联合账户,那这是一个非常棒的方案,但是,如果需要的是两个分离账户,就需要作些改动了。要得到一个完全拷贝或者说深拷贝--创建一个新的容器对象,包含原有对象元素以及所有嵌套元素全新的拷贝--需要 copy.deepcopy()函数。我们使用深拷贝来重写整个例子。

注意: 上面示例中你可能认为深拷贝的列表中的第一个元素和原列表的id值不应该一样。首先肯定的是你的理解是没有问题的,只是Python为了优化效率,在解释器内提前初始化了一些常用的字符串,包括 'name',所以person、hubby、wifey的第一个元素都指向了Python解释器提前初始化的'name'对象。如果是更复杂的字符串,其id值就会不一样了。

注意: 第一,非容器类型(比如数字,字符串和其他"原子"类型的对象,像代码,类型和 xrange 对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的。第二,如果元组变量只包含原子类型对象,对它的深拷贝将不会进行。如果我们把账户信息改成元组类型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝。


《Python基础手册》系列:

Python基础手册 1 —— Python语言介绍
Python基础手册 2 —— Python 环境搭建(Linux)
Python基础手册 3 —— Python解释器
Python基础手册 4 —— 文本结构
Python基础手册 5 —— 标识符和关键字
Python基础手册 6 —— 操作符
Python基础手册 7 —— 内建函数
Python基础手册 8 —— Python对象
Python基础手册 9 —— 数字类型
Python基础手册10 —— 序列(字符串)
Python基础手册11 —— 序列(元组&列表)
Python基础手册12 —— 序列(类型操作)
Python基础手册13 —— 映射(字典)
Python基础手册14 —— 集合
Python基础手册15 —— 解析
Python基础手册16 —— 文件
Python基础手册17 —— 简单语句
Python基础手册18 —— 复合语句(流程控制语句)
Python基础手册19 —— 迭代器
Python基础手册20 —— 生成器
Python基础手册21 —— 函数的定义
Python基础手册22 —— 函数的参数
Python基础手册23 —— 函数的调用
Python基础手册24 —— 函数中变量的作用域
Python基础手册25 —— 装饰器
Python基础手册26 —— 错误 & 异常
Python基础手册27 —— 模块
Python基础手册28 —— 模块的高级概念
Python基础手册29 —— 包

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容