python 列表构造时的引用问题
以前老是不注意python对象引用,平时也没遇到这样的问题,昨天在这个小问题纠结了半天时间。真是TMD啊
先说明一下我的目的,我有一个包含16个元素的列表,每个元素也是一个小列表。我想每四个子列表为一个单位,改变每个子列表的第一个元素为我想要的值。
代码如下
>>>a = range(1,5)
>>>b = [[0]*3]*16
>>>for i in range(4):
each = b[i*4:(i+1)*4]
for item in each:
item[0]=a[i]
print it
[1, 0, 0]
[1, 0, 0]
[1, 0, 0]
[1, 0, 0]
[2, 0, 0]
[2, 0, 0]
[2, 0, 0]
[2, 0, 0]
[3, 0, 0]
[3, 0, 0]
[3, 0, 0]
[3, 0, 0]
[4, 0, 0]
[4, 0, 0]
[4, 0, 0]
[4, 0, 0]
嗯,是我想看到的结果,可是我想要的不是打印出来,可是我把b打印出来,我去,怎么成下面这个鸟样
[[4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0]]
于是我分析了几遍那两个for循环,都开始怀疑电脑是不是坏了。。。最后也没分析出个结果,于是我上开源中国那求助了,结果是我自己构造列表时就错了。
b = [[0]*3]*16这种方法构造的列表,十六个元素都是列表中第0个元素的引用,并没有真的开辟新的空间:b[0] is b[1] 会返回True,is好似通过对象的id来判断是否同一个对象,也就是说b[0]和b[1]的id是相同的。
那么这种构造列表方法就真的达不到我的目的了?no,no,no!python复制里有浅复制和深复制。这种构造方法就是列表中后面的元素浅复制了第一个元素。我们只要在后面的for循环里引入深复制,即可达到目的。
>>>b1= []
>>> for i in range(4):
each = copy.deepcopy(b[i*4:(i+1)*4])
for item in each:
item[0]=a[i]
b1.append(item)
>>> b1
>>>[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [3, 0, 0], [3, 0, 0], [3, 0, 0], [3, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0]]
不过这种方法归根接底并没有解决上面的构造列表时对象引用时钱复制的问题,因为这样以后b列表还是所有元素都和第0 个元素一样。
下面我们换种构造列表的方法,递推式构造列表。
>>> b = [[0]*3 for i in range(16)]
>>> b
>>>[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
虽然看起来和上一种方法一个鸟样,但这只是表象。
用b[0] is b[1] 验证一下,果然返回的是False。说明这种构造方法会给推导式中每个元素都开辟新的空间,也就是说b[0]和b[1]的id是不同的。
for i in range(4):
each = b[i*4:(i+1)*4]
for item in each:
item[0]=a[i]
>>> b
>>>[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [2, 0, 0], [3, 0, 0], [3, 0, 0], [3, 0, 0], [3, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0]]
用这种方法构造的时,没有调用deepcopy这个方法,就可以达到效果。。。
总结一下:构造列表时注意,使用乘号构造是钱复制,所有对象都引用第0个元素,使用列表推导时直接开辟新空间,不存在复制不复制。
想了解python的复制及对象引用可以参考http://www.cnblogs.com/BeginMan/p/3197649.html
python 列表构造时的引用问题的更多相关文章
- Python 列表切片陷阱:引用、复制与深复制
Python 列表的切片和赋值操作很基础,之前也遇到过一些坑,以为自己很懂了.但今天刷 Codewars 时发现了一个更大的坑,故在此记录. Python 列表赋值:复制"值"还是 ...
- python 列表和字典的引用与复制(copy)
列表或字典的引用: 引用针对变量的时候,传递引用后,对引用后的对象的值进行改变是不会影响到原值的:而列表不一样如: spam =42 cheese = spam spam =100 print(spa ...
- Python列表,元组,字典,序列,引用
1.列表 # Filename: using_list.py # This is my shopping list shoplist=["apple", "mango&q ...
- python列表与集合,以及循环时的注意事项
一.python列表 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,往后数的最后一个为-1依此类推. Python有6个序 ...
- 使用gc、objgraph干掉python内存泄露与循环引用!
Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问 ...
- python列表类型
列表类型简介 列表类型是一个容器,它里面可以存放任意数量.任意类型的数据. 例如下面的几个列表中,有存储数值的.字符串的.内嵌列表的.不仅如此,还可以存储其他任意类型. >>> L ...
- Python列表、元组、字典和字符串的常用函数
Python列表.元组.字典和字符串的常用函数 一.列表方法 1.ls.extend(object) 向列表ls中插入object中的每个元素,object可以是字符串,元组和列表(字符串“abc”中 ...
- python 列表与元组的操作简介
上一篇:Python 序列通用操作介绍 列表 列表是可变的(mutable)--可以改变列表的内容,这不同于字符串和元组,字符串和元组都是不可变的.接下来讨论一下列表所提供的方法. list函数 可以 ...
- python 深入理解 赋值、引用、拷贝、作用域
在 python 中赋值语句总是建立对象的引用值,而不是复制对象.因此,python 变量更像是指针,而不是数据存储区域, 这点和大多数 OO 语言类似吧,比如 C++.java 等 ~ 1.先来看个 ...
随机推荐
- 用virtualenv建立多个Python独立开发环境(转)
add by zhj: 在virtualenv环境下,安装第三方包时,不要用sudo pip install xxx,要直接用pip install xxx,如果用sudo时,那会安装在原来的系统Py ...
- 【我的Android进阶之旅】解决Android Studio 运行gradle命令时报错: 错误: 编码GBK的不可映射字符
1.问题描述 最近在负责公司基础业务和移动基础设施的开发工作,正在负责Lint代码静态检查工作.因此编写了自定义的Lint规则,在调试过程中,编译的时候出现了如下所示的错误: 部分输出日志如下所示: ...
- Oracle SQL语句积累
字段合并: select EVFOUNDATIONTYPEA || EVFOUNDATIONTYPEB|| EVFOUNDATIONTYPEC ||EVFOUNDATIONTYPED as b fro ...
- Flask上下文管理及源码刨析
基本流程概述 - 与django相比是两种不同的实现方式. - django/tornado是通过传参数形式实现 - 而flask是通过上下文管理, 两种都可以实现,只不实现的方式不一样罢了. - 上 ...
- Linux 中的 Service
参考: cnblogs.com/xiaofan21 - linux service和daemon cnblogs.com/xuange306 - linux service命令常见使用方法 cnblo ...
- ZW网络团队及资源简介
ZW网络团队及资源简介 ZW网络推广团队,是国内首个教父级网络营销团队,自1997年以来,先后参与操盘多个重大互联网项目,服务过超过150家国际500强客户,是微软公司首家官方认证的网络公关服务商,新 ...
- Python:执行精确的浮点数运算
需要对浮点数执行精确的计算操作,并且不希望有任何小误差的出现. 浮点数的一个普遍问题是它们并不能精确的表示十进制数.并且,即使是最简单的数学运算也会产生小的误差,比如: >>> a ...
- javascript模式(1)--私有成员
javascript是基于对象的一门语言,没有想java等语言那样子拥有封装的特性.但是javascript可以通过闭包来进行模拟. 1.构造函数与私有成员 可以用构造函数形成一个闭包,实现内部成员的 ...
- web上的复制
你可能曾经尝试过复制网页上的一些文字,得到的却是令人沮丧的的结果.这篇文章介绍相关的内容. 不是真正的文字 这可能是最常见的问题,很多人尝试对一张带有文字的图片进行像文字那样的选择,复制当然不行了. ...
- RESTful源码笔记之RESTful Framework的Mixins小结
0x00 引言 本篇对drf中的mixins进行简要的分析总结.Mixins在drf中主要配合viewset共同使用,实现http方法与mixins的相关类与方法进行关联. from rest_fra ...