专栏首页小小挖掘机列表的常用操作,这十张图把它说的明明白白!

列表的常用操作,这十张图把它说的明明白白!

列表( list)作为Python中最常用的数据类型之一,是一个可增加、删除元素的可变(mutable)容器。

基本操作

创建 list 的方法非常简单,只使用一对中括号[]

如下创建三个list:

empty = []
lst = [1,'xiaoming',29.5,'17312662388']
lst2 = ['001','2019-11-11',['三文鱼','电烤箱']]

empty在内存中的示意图:

empty内存示意图

lst在内存中的示意图:

lst 内存示意图

lst2在内存中的示意图:

lst2 内存示意图

使用python的内置函数len求list内元素个数:

len(empty) # 0
len(lst) # 4
len(lst2) # 3

依次遍历lst内每个元素并求对应类型,使用for in对遍历,内置函数type得到类型:

for _ in lst:
    print(f'{_}的类型为{type(_)}')

打印结果如下,列表 lst 内元素类型有3种:

1的类型为<class 'int'>
xiaoming的类型为<class 'str'>
29.5的类型为<class 'float'>
17312662388的类型为<class 'str'>

因此,Python的列表不要求元素类型一致。

如何向 lst2 的第三个元素['三文鱼','电烤箱']内再增加一个元素'烤鸭'

首先,使用整数索引取出这个元素:

sku = lst2[2] # sku又是一个列表

sku变量位于栈帧中,同时指向lst2[2]:

然后,使用列表的append方法增加元素,append默认增加到 sku列表尾部:

sku.append('烤鸭')
print(sku) # ['三文鱼', '电烤箱', '烤鸭']

sku变量示意图

此时想在sku指定索引1处插入牛腱子,使用列表的insert方法:

sku.insert(1,'牛腱子')
print(sku) # ['三文鱼', '牛腱子', '电烤箱', '烤鸭']

sku变量示意图

在购买烤鸭和牛腱子后,发现超出双十一的预算,不得不放弃购买烤鸭,使用pop方法可直接移除列表尾部元素:

item = sku.pop() # 返回烤鸭
print(sku) # ['三文鱼', '牛腱子', '电烤箱']

1574822687219

发现还是超出预算,干脆移除三文鱼,pop因为只能移除表尾元素,幸好列表有remove方法:

sku.remove('三文鱼') # 更好用:sku.remove(sku[0])
print(sku) # ['牛腱子', '电烤箱']

sku变量示意图

深浅拷贝

打印 lst2,发现第三个元素也对应改变,因为 sku 引用 lst2 的第三个元素,sku 指向的内存区域改变,所以 lst2 也会相应改变。

print(lst2) # ['001', '2019-11-11', ['牛腱子', '电烤箱']]

如果不想改变 lst2 的第三个元素,就需要复制出 lst2 这个元素,列表上有 copy 方法可实现复制:

lst2 = ['001','2019-11-11',['三文鱼','电烤箱']] # 这是lst2的初始值

可视化此行代码,lst2 位于全局帧栈中,其中三个元素内存中的可视化图如下所示:

lst2变量示意图

sku_deep = lst2[2].copy() 

注意,copy 函数,仅仅实现对内嵌对象的一层拷贝,属于 shallow copy.

此时可视化图为如下,因为拷贝 lst2[2],所以 sku_deep 位于栈帧中指向一块新的内存空间:

sku_deep 示意图

此时,再对 sku_deep 操作,便不会影响 lst2[2] 的值。

如下修改 sku_deep 的第一个元素( Python 的列表索引从 0 开始编号), lst2 未受到任何影响。

sku_deep[0] = '腱子'
print(lst2[2]) # ['三文鱼','电烤箱']

修改 sku_deep 时,不会影响 lst2[2].

因为它们位于不同的内存空间中,如图所示,lst2[2] 中的第一个元素依然是 三文鱼,而不是腱子.

浅拷贝示意图

至此,仅仅使用 shallow copy.

那么,它与深拷贝 ,英文叫 deepcopy,又有什么不同?

请看下面例子, a 是内嵌一层 list 的列表,对其浅拷贝生成列表 ac,修改 ac 的第三个元素,也就是列表 [3,4,5] 中的第二个元素为 40

a = [1,2,[3,4,5]]
ac = a.copy()
ac[0] = 10
ac[2][1] = 40

修改后,分别测试两个值的相等性。

print(a[0] == ac[0])

返回 False ,证明实现拷贝。

ac[2][1]是否与原数组 a 的对应位置元素相等:

print(a[2][1] == ac[2][1])

返回 True,进一步证明是浅拷贝,不是深拷贝。

如下图所示:copy 只完成了一层 copy,即 [1,2, id([3,4,5])] 复制一份,而复制后,仍然指向 [3,4,5] 所在的内存空间:

要想实现深度拷贝,需要使用 copy 模块的 deepcopy 函数:

from copy import deepcopy

a = [1,2,[3,4,5]]
ac = deepcopy(a)
ac[0] = 10
ac[2][1] = 40
print(a[0] == ac[0])
print(a[2][1] == ac[2][1])

打印结果,都为 False,结合下图,也能看出内嵌的 list 全部完成复制,都指向了不同的内存区域。

以上图文介绍 list 的基本操作和深浅拷贝问题。

本文分享自微信公众号 - 小小挖掘机(wAIsjwj)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 论文|组推荐系统及其应用研究

    这篇文章主要是说明一下群组推荐系统,众所周知,推荐系统已经应用十分广泛,群组推荐的应用不仅老用户上发挥了极大的作用,在新用户的冷启动上也发挥了很大的作用。

    石晓文
  • 推荐三款机器学习论文搜索利器

    简单介绍:arXiv是个提交论文预印本(preprint)的平台,里面的论文都没有经过同行评审(peer review),所以文章质量参差不齐,但却会比较新颖,...

    石晓文
  • 深度学习两大基础Tricks:Dropout和BN详解

    dropout作为目前神经网络训练的一项必备技术,自从被Hinton提出以来,几乎是进行深度学习训练时的标配。就像做菜时必须加料酒一样,无论何时,大家...

    石晓文
  • 逻辑回归 – Logistic regression

    逻辑回归(Logistic Regression)主要解决二分类问题,用来表示某件事情发生的可能性。

    easyAI
  • 用户体验杂谈(4)

    本文以及(1)(2)(3)系发表于2017年6月8日之前,是在架构变化之前。

    RP道貌不岸然
  • 面试官:同学,说说 Applink 的使用以及原理

    通过 Link这个单词我们可以看出这个是一种链接,使用此链接可以直接跳转到 APP,常用于应用拉活,跨应用启动,推送通知启动等场景。

    个推君
  • 聊聊CanalInstanceGenerator

    canal-1.1.4/instance/core/src/main/java/com/alibaba/otter/canal/instance/core/Ca...

    codecraft
  • ThinkPHP6.0学习笔记-验证器

    scene支持为单个场景单独定义方法,方法的命名规范是scene+场景名,采用驼峰写法;

    Mirror王宇阳
  • 聊聊CanalInstanceGenerator

    canal-1.1.4/instance/core/src/main/java/com/alibaba/otter/canal/instance/core/Ca...

    codecraft
  • 使用C语言编写Python扩展包

    使用C编写Python扩展包。官网文档其实已经很详尽~ 使用场景猜想:某些需要高效处理的算法、某些耗时的操作优化、或者某些核心算法加密等~

    lpe234

扫码关注云+社区

领取腾讯云代金券