首先,不用解释器,脑补一下下面这段代码的结果是什么
1 2 3 4 5 6 7 8 |
def add(lst1,lst2): for i in xrange(len(lst1)): lst1[i]+=lst2[i] a=[[0]*3]*3 add(a[0],[1,0,0]) add(a[1],[0,1,0]) print a[1] |
有没有娃儿和我一样觉得是[0,1,0]的?
实际上结果出人意料地是[1,1,0]
WTF!昨天晚上我想了三宿都没明白Σ(`д′*ノ)ノ 后来吃了一个橙子终于想通了
a=[[0]*3]*3这句话来将a赋值成 [[0,0,0],[0,0,0],[0,0,0]],然而python似乎是这样赋值的:
为了验证这个猜想我们用内置函数id来打印内存地址(仅对cpython而言)
1 2 3 4 5 6 |
>>> id(a[0]) 38025256 >>> id(a[1]) 38025256 >>> id(a[2]) 38025256 |
这证明了我们的猜想。
那么如果我用下面这句话来初始化a呢?
1 |
a=[[0]*3 for i in range(3)] |
这次直接看id:
1 2 3 4 5 6 |
>>> id(a[0]) 38056704 >>> id(a[1]) 38056744 >>> id(a[2]) 33504712 |
不一样了吧。可见使用列表推导式时,每次都会重新计算一次[0,0,0]的值(在这个例子中它不随i变化),而不会去引用之前的结果;或者说,*运算符作用于列表时产生n个对原对象的引用,而不是真正的复制
还有个有趣的现象
1 2 3 4 5 |
>>> a=1 >>> id(a) 38176416 >>> id(1) 38176416 |
真特么抠门,真不知道cpython的内存回收是怎么做的,有空去看看源码(* ̄︶ ̄)y