序列赋值引发的Python列表陷进
序列赋值是Python默认操作,如果使用不当,有可能会掉入语法陷阱。
+
+
是指把两个序列的元素拼接在一起。通常+号两侧的序列由相同类型的数据所构成,在拼接的过程中,两个被操作的序列都不会被修改,Python会新建一个包含同样类型数据的序列作为拼接的结果。比如:
a = [1]
b = [2]
c = a + b
print(a, b, c)
print(id(a), id(b), id(c))
结果为:
[1] [2] [1, 2]
2409610524480 2409610523520 2409610523648
*
如果想要把一个序列复制几份然后再拼接起来,更快捷的做法是把这个序列乘以一个整数。同样,这个操作会产生一个新序列:
>>> l = [1]
>>> l * 5
[1, 1, 1, 1, 1]
>>> 5 * "a"
'aaaaa'
+
和*
都遵循这个规律,不修改原有的操作对象,而是构建一个全新的序列。
列表套列表的陷进
猜猜这个结果会是啥:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
x = ["x"]
my_list = [x] * 3
print(my_list) # [['x'], ['x'], ['x']] x2 = my_list[2]
x2[0] = "y"
print(my_list)
讲道理,应该是[[‘x’], [‘x’], [‘y’]],但是错了,实际是:
[['y'], ['y'], ['y']]
Unbelievable!给my_list
的最后一个元素的列表赋值,结果所有三个元素的列表都被赋值了!这反映出my_list
这三个元素不是3个列表,而是3个列表引用,指向了同一个相同的列表。相当于:
x = ["x"]
my_list = []
for i in range(3): my_list.append(x) # 追加相同对象 x2 = my_list[2]
x2[0] = "y"
print(my_list) # [['y'], ['y'], ['y']]
每次都追加了同一个对象到my_list
。如果想生成3个不同列表,那么需要在每次迭代中新建列表:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
my_list = []
for i in range(3): x = ["x"] # 新建列表 my_list.append(x) x2 = my_list[2]
x2[0] = "y"
print(my_list) # [['x'], ['x'], ['y']]
这样就符合预期了。可以用列表推导简化代码:
x = ["x"]
my_list = [x for i range(3)] x2 = my_list[2]
x2[0] = "y"
print(my_list) # [['x'], ['x'], ['y']]
教训:
新建列表中的列表,使用列表推导,不要使用*运算符。
如果a * n
这个语句中,序列a里的元素是对其他可变对象的引用的话,就需要格外注意了,这可能不是你想要的效果。
+=
a += b虽然意思是a = a + b,但是它背后的特殊方法是__iadd__
,如果一个类没有实现这个方法的话,Python才会退一步调用__add__
。__iadd__
方法会直接在原对象中追加,__add__
方法会先生成新对象再赋值。
*=
+=
的这些概念也适用于*=
,只是后者对应的是__imul__
。追加还是新对象,在作用到可变序列和不可变序列时效果明显,示例:
# 可变序列,追加
>>> l = [1, 2, 3]
>>> id(l)
2135319475136
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
2135319475136 # id一样 # 不可变序列,新对象
>>> t = (1, 2, 3)
>>> id(t)
2135322139520
>>> t *= 2
>>> id(t)
2135321695424 # id不一样
元组套列表的陷进
>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]
猜猜会发生下面4种情况中的哪一种?a.t变成(1, 2, [30, 40, 50, 60])b
.因为tuple不支持对它的元素赋值,所以会抛出TypeError异常c.以上两个都不是d.a和b都是对的因为元组不能赋值,所以我会毫不犹豫的选择b。但实际上答案是d!a和b都是对的,既会赋值成功,也会报错:
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]
Traceback (most recent call last): File "<input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])
Oh No!为什么?
一、赋值成功,因为t[2]指向的是一个可变对象(列表[30, 40]),可变对象是能赋值的。
二、报错,因为可变对象赋值给了不可变对象(元组t),不可变对象不能赋值。
写成t[2].extend([50, 60])能避免这个异常。
教训:
- 不要把可变对象放在元组里面。
- +=不是一个原子操作,虽然抛出了异常,但还是完成了操作。
这位巴西作者说到,在他15年的Python生涯中,他还没见过谁在这个地方吃过亏。
小结
本文分别介绍了+
、*
和列表套列表的陷阱,+=
、*=
和元组套列表的陷阱,并分别得出了教训。这是动态语言的弊端,在运行后才能知道有没有类型错误,只能积累代码经验来避免。鱼与熊掌不可兼得,在享受Python语法简洁的便利同时,也得付出运行报错排查麻烦的代价。
序列赋值引发的Python列表陷进相关推荐
- python慕课笔记_MOOC python笔记(三) 序列容器:字符串、列表、元组
Python Python开发 Python语言 MOOC python笔记(三) 序列容器:字符串.列表.元组 容器概念 容器是Python中的重要概念,分为有序与无序. 有序容器也称为序列类型容器 ...
- python列表赋值 连续整数_Python_03_字符串_数据类型_for循环_列表操作
个人笔记,仅作学习记录,如有错误烦请指正 字符串: str1 = "这是一个字符串"str2= '这也是一个字符串' 一般字符串都需要用双引号或单引号引起来 在Python中双引号 ...
- python两个元组相加_《第5章 Python 列表与元组》5.1.3 序列相加(Adding)!
<高中信息技术 Python编程> 教学案<第5章 Python 列表与元组> 5.1.3 序列相加(Adding)! 06:15 1 #使用加号可以进行序列的连接操作,输入如 ...
- python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...
Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...
- python中有那几种赋值_详解Python列表赋值复制深拷贝及5种浅拷贝
概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅拷贝.深拷贝等绕口的名词到底有什么区别和作用呢? 列表赋值 # 定义一个新 ...
- python序列类型包括哪三种映射类型_Python序列类型包括字符串、列表和元组三种,列表是Python中唯一的映射类型...
Python序列类型包括字符串.列表和元组三种,列表是Python中唯一的映射类型 更多相关问题 [填空题] 秦以后的地方基本建制为().但西汉因分封形成了(). [单选] 药物过敏性口炎的临床特征为 ...
- Python实战从入门到精通第三讲——数据结构与算法1之解压序列赋值
1.解压序列赋值给多个变量 任何的序列可以通过一个简单的赋值语句解压并赋值给多个变量,唯一前提是变量数与序列元素相同 data = ['ACME',50,91.1,(2012,12,21)] name ...
- python中将一个列表赋值给另一个列表
在写杨辉三角时,希望将一个列表直接赋值给另一个列表,就尝试写了一下. list1 = ['1', '2', '3'] list2 = list1 print(list1) print(list2) 运 ...
- 【Python学习教程】Python列表(list)、元组(tuple)、字典(dict)和集合(set)详解
文章目录 什么是序列,Python序列详解(包括序列类型和常用操作) 序列索引 序列切片 序列相加 序列相乘 检查元素是否包含在序列中 和序列相关的内置函数 Python list列表详解 Pytho ...
最新文章
- 在Ant-design-pro框架中引入jQuery和jQuery-ui步骤
- mysql触发器trigger
- 彭博社:中企游说政府否决英伟达收购Arm
- 7-6 实现图形接口及多态性 (30 分)
- Cleanmymac X最新版 Macbook“垃圾”清理软件
- linux中的ps fx命令,Linux中的ps命令
- linux 监控报文命令 nc,linux监控命令nc用法
- Java博客项目(重点)
- 鼠标放上去会变色的按钮
- 服务器硬盘故障问题有哪些
- 添加myenv至jupyter notebook kerne
- 11_MySQL笔记-主从复制-延迟备份-读写分离
- 第四方支付平台哪个好?这类第四方支付或惨遭淘汰
- vue中mint-ui使用详解
- [day4]python网络爬虫实战:爬取美女写真图片(Scrapy版)
- MapReduce通俗理解
- 金融历史数据导入之股票 level2 逐笔篇
- 计算机主机上授权许可标签,计算机安装软件抽查登记表填表及操作说明.DOC
- php空间xpyun_php云人才系统官方版-phpyun下载 v4.0 官方正式版 - 安下载
- opera关闭价格或房型