返回介绍

原处修改列表

发布于 2024-01-29 22:24:16 字数 4465 浏览 0 评论 0 收藏 0

由于列表是可变的,它们支持原处改变列表对象的操作。也就是说,本节中的操作都可以直接修改列表对象,而不会像字符串那样强迫你建立一个新的拷贝。因为Python只处理对象引用,所以需要将原处修改一个对象与生成一个新对象区分开来,这在第6章已经讨论过了,如果你在原处修改一个对象时,可能同时会影响一个以上指向它的引用。

索引与分片的赋值

当使用列表的时候,可以将它赋值给一个特定项(偏移)或整个片段(分片)来改变它的内容:

索引和分片的赋值都是原地修改,它们对列表进行直接修改,而不是生成一个新的列表作为结果。Python中的索引赋值与C及大多数其他语言极为相似——Python用一个新值取代指定偏移的对象引用。

上一个例子的最后一个操作是分片赋值,它仅仅用一步操作就能够将列表的整个片段替换掉。因为这可能有点复杂,所以分片赋值最好分成两步来理解:

1.删除。删除等号左边指定的分片。

2.插入。将包含在等号右边对象中的片段插入旧分片被删除的位置[1]

实际情况并非如此,但这有助于你理解为什么插入元素的数目不需要与删除的数目相匹配。例如,已知一个列表L的值为[1,2,3],赋值操作L[1:2]=[4,5]会把L修改成列表[1,4,5,3]。Python会先删除2(单项分片),然后在删除2的地方插入4和5。这也解释了为什么L[1:2]=[]实际上是删除操作——Python删除分片(位于偏移为1的项)之后什么也不插入。

实际上,分片赋值是一次性替换整个片段或“栏”。因为被赋值的序列长度不一定要与被赋值的分片的长度相匹配,所以分片赋值能够用来替换(覆盖)、增长(插入)、缩短(删除)主列表。这是功能强大的操作,然而坦率地说,它也是在实践当中不常见的操作。Python通常还有更简单直接的方式实现替换、插入以及删除(例如,合并、insert、pop以及remove列表方法),实际上那些才是Python程序员比较喜欢用的。

列表方法调用

与字符串相同,Python列表对象也支持特定类型方法调用,其中很多调用可以在原处修改主体列表:

在第7章里我们介绍过方法。简而言之,方法就是附属于特定对象的函数(实际上是引用函数的属性)。方法提供特定类型的工具。例如,我们这里介绍的列表方法只适用于列表。

可能最常用的列表方法是append,它能够简单地将一个单项(对象引用)加至列表末端。与合并不同的是,append允许传入单一对象而不是列表。L.append(X)与L+[X]的结果类似,不同的是,前者会原地修改L,而后者会生成新的列表[2]

另一个常见方法是sort,它原地对列表进行排序。sort是使用Python标准的比较检验作为默认值(在这里指字符串比较),而且以递增的顺序进行排序。

我们可以通过传入关键字参数来修改排序行为——这是指定按名称传递的函数调用中特殊的"name=value"语法,常常用来给定配置选项。在排序中,key参数给出了一个单个参数的函数,它返回在排序中使用的值,reverse参数允许排序按照降序而不是升序进行:

当排序字典的列表的时候,排序的key参数也很有用,可以通过索引每个字典挑选出一个排序键。我们将在本章稍后学习字典,并且将在本书第四部分了解关于关键字函数参数的更多内容。

注意:Python 3.0中的比较和排序:在Python 2.6和更早的版本中,不同类型的对象也是可进行比较的(例如,字符串和列表)——语言在不同类型之中都定义了一个固定的顺序,也许看上去并不那么赏心悦目,但它们是明确的。也就是说,这一次序是根据涉及的类型名称而定的。例如,所有整数都小于所有字符串,因为"int"比"str"小。比较运算时绝不会自动转换类型,除非是在比较数值类型对象。

在Python 3.0中,这一点可能就不一样了——不同类型的比较不再依赖于固定的跨类型之间的排序,而是引发一个异常。因为排序是在内部进行比较,这意味着[1,2,'spam'].sort()在Python 2.X中是能行得通的,但是在Python 3.0中则会发生异常。

Python 3.0也不再支持:传入一个任意的比较函数来进行排序以实现不同的顺序。建议的解决方法是使用key=func关键字参数在排序时编码值的转换,并且使用reverse=True关键字参数把排序顺序改为降序。这些都是过去比较函数的典型用法。

注意:要当心append和sort原处修改相关的列表对象,而结果并没有返回列表(从技术上来讲,两者返回的值皆为None)。如果编辑类似L=L.append(X)的语句,将不会得到L修改后的值(实际上,会失去整个列表的引用);当使用append和sort之类的属性时,对象的修改有点像副作用,所以没有理由再重新赋值。

一部分原因是这样的限制,排序也在最近的Python中可以作为内置函数使用了,它可以排序任何集合(不只是列表)并且针对结果返回一个新的列表(而不是原处修改):

注意这里的最后一个例子——我们可以用一个列表解析在排序之前转换为小写,但是结果不包含最初的列表的值,因为这是用key参数来实现的。后者在排序中临时应用,而不会改变排序的值。随着我们进一步学习,将会看到这样的情况,内置函数sorted有时候比sort方法更有用。

与字符串相同,列表有其他方法可执行其他特定的操作。例如,reverse可原地反转列表,extend和pop方法分别能够在末端插入多个元素、删除一个元素。也有一个reversed内置函数,像sorted一样地工作,但是,它必须包装在一个list调用中,因为它是一个迭代器(后面更详细地讨论迭代器):

在某些类型的应用程序中,往往会把这里用到的列表pop方法和append方法联用,来实现快速的后进先出(LIFO,last-in-first-out)堆栈结构。列表的末端作为堆栈的顶端:

pop方法也能够接受某一个即将删除并返回的元素的偏移(默认值为最后一个元素),这一偏移是可选的。其他列表方法可以通过值删除(remove)某元素,在偏移处插入(insert)某元素,查找某元素的偏移(index)等:

可以参考其他说明源文件或者多练习这些调用进行更深入的学习。

其他常见列表操作

由于列表是可变的,你可以用del语句在原处删除某项或某片段:

因为分片赋值是删除外加插入操作,也可以通过将空列表赋值给分片来删除列表片段(L[i:j]=[])。Python会删除左侧的分片,然后什么也不插入。另一方面,将空列表赋值给一个索引只会在指定的位置存储空列表的引用,而不是删除:

虽然刚才讨论的所有操作都很典型,但是还有其他列表方法和操作并没有在这里列出(包括插入和搜索方法)。为了得到更全面的最新类型工具清单,你应该时常参考Python手册、Python的dir和help函数(我们在第4章首次提到过),《Python Pocket Reference》(O'Reilly)以及其他在前言中所提到的参考书籍。

还想再次提醒你,我们这里讨论的原处修改操作都只适用于可变对象:无论你怎样绞尽脑汁,都是不能用在字符串上的(或者是第9章中我们将要讨论的元组)。可变性是每个对象类型的固有属性。

[1]当赋值的值与分片重叠时,就需要详细的分析:例如,L[2:5]=L[3:6]是可行的,这是因为要被插入的值会在左侧删除发生前被取出。

[2]和“+”合并不同的是,append不用产生新对象,所以执行起来通常比较快。你也可以用聪明的分片运算模拟append:L[len(L):]=[X]就与L.append(X)一样,而L[:0]=[X]就好像在列表前端附加那样。两者都会删除空分片,并插入X,快速地在适当之处修改L,就像append一样。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文