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.先来看个 ...
随机推荐
- hdu 5056 Boring count (窗体滑动)
You are given a string S consisting of lowercase letters, and your task is counting the number of su ...
- idea 设置
1.代码提示不区分大小写 2.自动导入 抽取成接口-push members up 你可能不知道的IDEA使用技巧
- MySQL和MSSQL差异(增量)备份的原理
MySQL和MSSQL差异(增量)备份的原理 对于真正的增量备份来说,只需要记录当前每页最后的检查点的LSN,如果大于之前全备时的LSN,则备份该页面,否则不用备份 这大大加快了备份速度和恢复时间,同 ...
- centos linux系统日常管理3 服务管理ntsysv,chkconfig,系统日志rsyslog,last ,lastb ,exec,xargs,dmesg,screen,nohup,curl,ping ,telnet,traceroute ,dig ,nc,nmap,host,nethogs 第十六节课
centos linux系统日常管理3 服务管理ntsysv,chkconfig,系统日志rsyslog,last ,lastb ,exec,xargs,dmesg,screen,nohup,cur ...
- java模拟网页http-url访问
package com.iflytek; import java.io.InputStream; import java.net.HttpURLConnection; import java.net. ...
- OpenStack功能简介
为什要用云? 一.简单的说就是对资源更加合理的分配,使用,比如硬件的数量,带宽等等这些,因为你不能机器买来不需要了再卖掉(当然也可以),带宽跟机房签合同得来一年的,中间不够了也不能加,超了也不退钱 二 ...
- Flask上下文管理及源码刨析
基本流程概述 - 与django相比是两种不同的实现方式. - django/tornado是通过传参数形式实现 - 而flask是通过上下文管理, 两种都可以实现,只不实现的方式不一样罢了. - 上 ...
- cocos代码研究(16)Widget子类RadioButton学习笔记
理论基础 RadioButton是一种特定类型的两状态按钮,它与复选框相似.它可以 和RadioButtonGroup一起使用,形成一个"组".继承自AbstractCheckBu ...
- 史上最强网推案例,没有之一【ZW团队实战经典】
ZW团队认为,互联网本质只有两个字:颠覆. ZW网络推广团队,是国内首个教父级网络营销团队,自1997年以来,先后参与操盘多个重大互联网项目,服务过超过150家国际500强客户,是微软公司首家官方认证 ...
- vue 基础笔记
Vue01笔记 ES6模块使用和新的函数声明方式 a) Import 一定不能放在函数内, 建议放在上方 b) Export 除了声明式的以外, 尽量放在代码的下方 Import {name,age} ...