序列赋值是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列表陷进相关推荐

  1. python慕课笔记_MOOC python笔记(三) 序列容器:字符串、列表、元组

    Python Python开发 Python语言 MOOC python笔记(三) 序列容器:字符串.列表.元组 容器概念 容器是Python中的重要概念,分为有序与无序. 有序容器也称为序列类型容器 ...

  2. python列表赋值 连续整数_Python_03_字符串_数据类型_for循环_列表操作

    个人笔记,仅作学习记录,如有错误烦请指正 字符串: str1 = "这是一个字符串"str2= '这也是一个字符串' 一般字符串都需要用双引号或单引号引起来 在Python中双引号 ...

  3. python两个元组相加_《第5章 Python 列表与元组》5.1.3 序列相加(Adding)!

    <高中信息技术 Python编程> 教学案<第5章 Python 列表与元组> 5.1.3 序列相加(Adding)! 06:15 1 #使用加号可以进行序列的连接操作,输入如 ...

  4. python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...

    Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...

  5. python中有那几种赋值_详解Python列表赋值复制深拷贝及5种浅拷贝

    概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅拷贝.深拷贝等绕口的名词到底有什么区别和作用呢? 列表赋值 # 定义一个新 ...

  6. python序列类型包括哪三种映射类型_Python序列类型包括字符串、列表和元组三种,列表是Python中唯一的映射类型...

    Python序列类型包括字符串.列表和元组三种,列表是Python中唯一的映射类型 更多相关问题 [填空题] 秦以后的地方基本建制为().但西汉因分封形成了(). [单选] 药物过敏性口炎的临床特征为 ...

  7. Python实战从入门到精通第三讲——数据结构与算法1之解压序列赋值

    1.解压序列赋值给多个变量 任何的序列可以通过一个简单的赋值语句解压并赋值给多个变量,唯一前提是变量数与序列元素相同 data = ['ACME',50,91.1,(2012,12,21)] name ...

  8. python中将一个列表赋值给另一个列表

    在写杨辉三角时,希望将一个列表直接赋值给另一个列表,就尝试写了一下. list1 = ['1', '2', '3'] list2 = list1 print(list1) print(list2) 运 ...

  9. 【Python学习教程】Python列表(list)、元组(tuple)、字典(dict)和集合(set)详解

    文章目录 什么是序列,Python序列详解(包括序列类型和常用操作) 序列索引 序列切片 序列相加 序列相乘 检查元素是否包含在序列中 和序列相关的内置函数 Python list列表详解 Pytho ...

最新文章

  1. 在Ant-design-pro框架中引入jQuery和jQuery-ui步骤
  2. mysql触发器trigger
  3. 彭博社:中企游说政府否决英伟达收购Arm
  4. 7-6 实现图形接口及多态性 (30 分)
  5. Cleanmymac X最新版 Macbook“垃圾”清理软件
  6. linux中的ps fx命令,Linux中的ps命令
  7. linux 监控报文命令 nc,linux监控命令nc用法
  8. Java博客项目(重点)
  9. 鼠标放上去会变色的按钮
  10. 服务器硬盘故障问题有哪些
  11. 添加myenv至jupyter notebook kerne
  12. 11_MySQL笔记-主从复制-延迟备份-读写分离
  13. 第四方支付平台哪个好?这类第四方支付或惨遭淘汰
  14. vue中mint-ui使用详解
  15. [day4]python网络爬虫实战:爬取美女写真图片(Scrapy版)
  16. MapReduce通俗理解
  17. 金融历史数据导入之股票 level2 逐笔篇
  18. 计算机主机上授权许可标签,计算机安装软件抽查登记表填表及操作说明.DOC
  19. php空间xpyun_php云人才系统官方版-phpyun下载 v4.0 官方正式版 - 安下载
  20. opera关闭价格或房型

热门文章

  1. 在CentOS6.9中 搭建 Flume
  2. esp8266 rtos sdk在小黄板上的使用
  3. ASP.NET实现微信功能(2)(服务号高级群发)
  4. oracle mysql sql serve where in 语句的不同
  5. [代码]ural 1655 Somali Pirates
  6. 【温故知新】CSS学习笔记(三大特性)
  7. 【转】SAP地产业正青春
  8. 采购订单更改日期的妙用
  9. 超级实用的列表提示错误一览显示框
  10. 生产模式MTOMTS的区别