以前老是不注意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 列表构造时的引用问题的更多相关文章

  1. Python 列表切片陷阱:引用、复制与深复制

    Python 列表的切片和赋值操作很基础,之前也遇到过一些坑,以为自己很懂了.但今天刷 Codewars 时发现了一个更大的坑,故在此记录. Python 列表赋值:复制"值"还是 ...

  2. python 列表和字典的引用与复制(copy)

    列表或字典的引用: 引用针对变量的时候,传递引用后,对引用后的对象的值进行改变是不会影响到原值的:而列表不一样如: spam =42 cheese = spam spam =100 print(spa ...

  3. Python列表,元组,字典,序列,引用

    1.列表 # Filename: using_list.py # This is my shopping list shoplist=["apple", "mango&q ...

  4. python列表与集合,以及循环时的注意事项

    一.python列表 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,往后数的最后一个为-1依此类推. Python有6个序 ...

  5. 使用gc、objgraph干掉python内存泄露与循环引用!

    Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问 ...

  6. python列表类型

    列表类型简介 列表类型是一个容器,它里面可以存放任意数量.任意类型的数据. 例如下面的几个列表中,有存储数值的.字符串的.内嵌列表的.不仅如此,还可以存储其他任意类型. >>> L ...

  7. Python列表、元组、字典和字符串的常用函数

    Python列表.元组.字典和字符串的常用函数 一.列表方法 1.ls.extend(object) 向列表ls中插入object中的每个元素,object可以是字符串,元组和列表(字符串“abc”中 ...

  8. python 列表与元组的操作简介

    上一篇:Python 序列通用操作介绍 列表 列表是可变的(mutable)--可以改变列表的内容,这不同于字符串和元组,字符串和元组都是不可变的.接下来讨论一下列表所提供的方法. list函数 可以 ...

  9. python 深入理解 赋值、引用、拷贝、作用域

    在 python 中赋值语句总是建立对象的引用值,而不是复制对象.因此,python 变量更像是指针,而不是数据存储区域, 这点和大多数 OO 语言类似吧,比如 C++.java 等 ~ 1.先来看个 ...

随机推荐

  1. 什么是虚拟DOM?

    (摘抄自一篇文章,觉得这里写得非常不错,所以单独放出来,希望能对大家有帮助.)React为啥这么大?因为它实现了一个虚拟DOM(Virtual DOM).虚拟DOM是干什么的?这就要从浏览器本身讲起 ...

  2. 怎么在Linux上抓包分析

    怎么在Linux上抓包分析 1.在Linux上抓包 例如在Ubuntu上,用命令抓包, tcpdump tcp  -i any -s0 -w desk.cap 用  sz desk.cap  把数据包 ...

  3. mysql 数据操作 单表查询 where约束 练习

    create table employee( id int not null unique auto_increment, name ) not null, sex enum('male','fema ...

  4. IOS #ifdef 的那些事儿

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u012884714/article/details/25188685 格式有点乱,整了几次都整只是来 ...

  5. centos Linux系统日常管理2 tcpdump,tshark,selinux,strings命令, iptables ,crontab,TCP,UDP,ICMP,FTP网络知识 第十五节课

    centos  Linux系统日常管理2  tcpdump,tshark,selinux,strings命令, iptables ,crontab,TCP,UDP,ICMP,FTP网络知识 第十五节课 ...

  6. poi根据模板导出word文档

    POI结构与常用类 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI ...

  7. 从WW中剥离一个三维场景框架

    从WW中剥离一个三维场景框架,初步实现的一个.可以绘制一个三角形,但是不能够控制摄像机,没有增加鼠标事件.没有投影,世界变幻之类的东西.以后会不断学习逐步增加进来. 下载地址 下载V1.0.0.2

  8. tar命令解压时如何去除目录结构及其解压到指定目录 (--strip-components N)

    去除目录结构加上 --strip-components N 如: 压缩文件eg.tar 中文件信息为 src/src/src/eg.txt 运行 tar -xvf eg.tar --strip-com ...

  9. (2)基本工作流(制作场景与UI)

    1.认识cocos编辑器主界面.   2.制作新场景:   1)打开我们新建的HelloCocos项目,新建场景名称为“Scene”,如下图:   2)点击新建,场景就被创建出来了,如下图:   3) ...

  10. 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017) Solution

    A - Airport Coffee 留坑. B - Best Relay Team 枚举首棒 #include <bits/stdc++.h> using namespace std; ...