[新手求助]list中的一些关于面向对象思想的疑问

190 views
Skip to first unread message

kaifeng jin

unread,
Oct 26, 2011, 9:01:06 AM10/26/11
to pyth...@googlegroups.com
最初在豆瓣讨论组里看到,但是没什么人讨论,还是有点疑惑:
>>> a=[[0]*3]*5
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
有人对这个现象的解释是[0,0,0]是一个对象,list中的5个[0,0,0]的引用都是指向同一个[0,0,0]对象,所以改变一个都会改变。我想问,那这样的话,[0]也是一个对象啊,[0]*3不也是对对象引用的拷贝吗?相当于三个引用指向[0]对象,那这样想的话,结果不是应该是[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]]吗?
越想越绕,希望大家给予指点

--
twitter:@zybest
新浪微博:@爱子悦

Yuan

unread,
Oct 26, 2011, 9:33:49 AM10/26/11
to pyth...@googlegroups.com
我的理解是这样,
a=[[0]*3]*5=[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
a[0][0]=[0,0,0][0]*5=1
a[0] 是*3的展开,而a[0][0]则是[0,0,0]*5 的第一个元素
所以结果是[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]] 
>_>
Best regards
-------------------------
Yuan blog github






2011/10/26 kaifeng jin <jkf...@gmail.com>

--
来自: python-cn`CPyUG`华蟒用户组(中文Python技术邮件列表)
发言: pyth...@googlegroups.com
退订: python-cn+...@googlegroups.com (向此发空信即退!)
详情: http://code.google.com/p/cpyug/wiki/PythonCn
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
强烈: 建议使用技巧: 如何有效地报告Bug
http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html

Dongkuo Ma

unread,
Oct 26, 2011, 9:39:14 AM10/26/11
to pyth...@googlegroups.com
list 的*操作是shadow copy
生成的每个元素都和基础元素指向同一块内存区域
int是不可变的, a[0][0]=1,直接将[0,0,0]的第一个元素指向另一块区域
而list是可变的,a[0]的值变了,a[1],a[2]都和a[0]指向同一块区域,所以也跟着变了

2011/10/26 kaifeng jin <jkf...@gmail.com>

kaifeng jin

unread,
Oct 26, 2011, 9:57:26 AM10/26/11
to pyth...@googlegroups.com
大概明白了,意思是不是就是:
n1=0
n2=0
虽然都是指向0对象,但由于int是不可变的,当n2=1时,n1还是等于0,只是n2指向了1对象处。所以不会出现[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]]

Dongkuo Ma

unread,
Oct 26, 2011, 10:10:16 AM10/26/11
to pyth...@googlegroups.com

>>> l = [0,0,0]
>>> id(l)
3077662156L
>>> id(l[0])
159087988
>>> id(l[1])
159087988
>>> l[0] = 1
>>> id(l)
3077662156L
>>> id(l[0])
159087976

 l[0] = 1执行后,l[0]的id变了,而l的没有变


2011/10/26 kaifeng jin <jkf...@gmail.com>

pansz

unread,
Oct 27, 2011, 1:49:58 AM10/27/11
to pyth...@googlegroups.com
2011/10/26 kaifeng jin <jkf...@gmail.com>:

> 最初在豆瓣讨论组里看到,但是没什么人讨论,还是有点疑惑:
>>>> a=[[0]*3]*5
> 有人对这个现象的解释是[0,0,0]是一个对象,list中的5个[0,0,0]的引用都是指向同一个[0,0,0]对象,所以改变一个都会改变。我想问,那这样的话,[0]也是一个对象啊,[0]*3不也是对对象引用的拷贝吗?相当于三个引用指向[0]对象,那这样想的话,结果不是应该是[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]]吗?

这个问题我的解释就是:只有两重 list 的 * 操作才会出现引用拷贝问题。一重 list 是值拷贝的。

因此 [0] * 3 ,此过程发生的是值拷贝, [0] *3 *5 也是值拷贝,只有 [[0]*3]*5,这样的两重 list,在内层
list 中会存在引用拷贝的问题。

HYRY

unread,
Oct 27, 2011, 2:13:10 AM10/27/11
to pyth...@googlegroups.com
这个解释不正确。list的乘法是复制引用。  [0]*3是创建一个三个元素都引用对象0的list。只不过0是一个不可变的对象,因此这样做没有问题。你可以试试下面的代码:

class A(object):
    pass

alist = [A()] * 5

print alist

依云

unread,
Oct 27, 2011, 2:16:46 AM10/27/11
to pyth...@googlegroups.com

我不认同这样的理解。

[[0]*3]*5 是
L1 = [0]
L2 = L1 + L1 + L1
= [0, 0, 0]
L3 = [L2]
L4 = L3 + L3 + L3 + L3 + L3
= [L2, L2, L2, L2, L2]

别管 C++/Java 的引用拷贝和值拷贝之类的东西。在 Python 里,变量就是对象的
名字。很明显 L4 中是五个 L2,你不管叫哪个都是那个对象。就像一个人可以有
很多不同的职位,你不管通过哪个职位找到的人都是他。你通过他的职位 A 把那
个人找到,然后与他交换了一件物品。当你再通过另一个职位找到他时,他当然依
旧还是拥有那件礼品(L4[0][1] = 1; print L4[1][1])。人家有三件物品(比如
三只一样的杯具),你把他的第一件交换走了,另外两件当然还在那儿。

--
Best regards,
lilydjwg

Linux Vim Python 我的博客
http://lilydjwg.is-programmer.com/

pansz

unread,
Oct 27, 2011, 4:01:57 AM10/27/11
to pyth...@googlegroups.com
2011/10/27 依云 <lily...@gmail.com>:

> 旧还是拥有那件礼品(L4[0][1] = 1; print L4[1][1])。人家有三件物品(比如
> 三只一样的杯具),你把他的第一件交换走了,另外两件当然还在那儿。

了解了,确实我的理解错误,楼主那个情况的真正问题在于 a[0][0] = 1 只是交换了这一件物品,也就是说把 1 取出来把 0
放进去了,而不是把 0 改成了 1。

如果楼主的问题里面,把所有的 0 都换成某个对象,然后调用对象的某个方法去修改对象本身(而不是把对象替换成另外一个对象),这样就会发现 15 个对象全部更改了。

Reply all
Reply to author
Forward
0 new messages