这是一段测试代码
li1 = []
li2 = []
ki = [0]
j = 0
for i in range(10):
ki[0] = ki[0]+1
j = j+1
li1.append(ki)
li2.append(j)
print(li1)
print(li2)
这是输出:
[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
为何 append()参数是列表类型时,每次循环都会改变 li1 中的值???
1
laoyur 2016-11-20 09:37:55 +08:00 1
li1 = []
li2 = [] ki = [0] j = 0 for i in range(10): ki[0] = ki[0]+1 j = j+1 li1.append(list(ki)) li2.append(j) print(li1) print(li2) |
2
kindjeff 2016-11-20 09:38:39 +08:00 via iPhone 1
因为你只是 append 了 ki 对象的引用,而 list 是可变的,内容改变了,你 append 的进去的仍然是 ki 的引用。
|
4
exoticknight 2016-11-20 10:06:41 +08:00 1
明显是没搞清楚 python 是引用优先的
估计楼主肯定还会在用默认参数是对象的时候出现问题 |
5
woniu127 OP @exoticknight 学 python 还不够,认识还不够深,只能一个坑一个坑的踩了
|
6
BiggerLonger 2016-11-20 10:19:18 +08:00 via Android
應該是用 list.extend 方法
|
7
wwqgtxx 2016-11-20 10:24:42 +08:00
又一个被 C 的值传递坑的
|
8
IanPeverell 2016-11-20 10:53:46 +08:00 1
因为 append(ki)的时候传递的是 ki 的地址,所以如果想不改变值可以这么些 li.append([x for x in ki])
|
9
mornlight 2016-11-20 10:58:09 +08:00 via iPhone 1
第一个 list 里到最后是 10 个指向同一块内存的相同元素
|
10
dtfm 2016-11-20 11:15:46 +08:00 1
```
li1 = [] li2 = [] ki = [0] j = 0 for i in range(10): ki[0] = ki[0]+1 j = j+1 li1.append(ki[0]) li2.append(j) print(li1) print(li2) ``` 在 ki 里面加一个 ki[0],这样每次都添加就好了 |
11
lzhCoooder 2016-11-20 11:29:45 +08:00 1
浅拷贝 你 li1 里的每个元素都是指向的或者说引用的同一个 ki
li2 里之所以不这样 是因为 j 是不可变类型,没加一次创建一个新 j |
12
rebirth2 2016-11-20 12:40:51 +08:00 via Android 1
可以用 list slice, ki[:]这样直接创建新 list ,不过比较黑科技。。
|
13
onlyice 2016-11-20 13:02:14 +08:00 via Android
把代码粘贴到这里看看就懂了 http://www.pythontutor.com/visualize.html#py=2
|
14
bravecarrot 2016-11-20 13:13:10 +08:00
@onlyice 这个有意思啊 哈哈哈哈 不用开 ide 看了
|
15
bravecarrot 2016-11-20 13:25:14 +08:00 1
@woniu127 ls 的 @exoticknight 可能说的是这个
``` python def foo(x, l = []): l.append(x) return l y = foo(6) z = foo(8) p = foo(2, [3]) q = foo(4, [5]) print y print z print p print q ``` output: [6, 8] [6, 8] [3, 2] [5, 4] ************* 同理,函数每次使用的默认参数的 list 都是同一个,每次都会操作它 |
16
20015jjw 2016-11-20 15:34:28 +08:00
lz 你显然没理解 reference 的概念..
|
17
enenaaa 2016-11-21 09:10:23 +08:00
我也觉得奇怪,其他语言标准库的 append 函数多半是值插入, python 非得是引用。
然后用个不常见 extend 函数代替。 比较坑 |
18
diydry 2016-11-21 16:18:09 +08:00 1
对象变动(Mutation)
Python 中可变(mutable)与不可变(immutable)的数据类型让新⼿很是头痛。 简单的说, 可 变(mutable)意味着"可以被改动", ⽽不可变(immutable)的意思是“常量(constant)”。 想把脑 筋转动起来吗? 考虑下这个例⼦: foo = ['hi'] print(foo) # Output: ['hi'] bar = foo bar += ['bye'] print(foo) # Output: ['hi', 'bye'] 刚刚发⽣了什么? 我们预期的不是那样!我们期望看到是这样的: foo = ['hi'] print(foo) # Output: ['hi'] bar = foo bar += ['bye'] print(foo) # Output: ['hi'] print(bar) # Output: ['hi', 'bye'] 这不是⼀个 bug 。 这是对象可变性(mutability)在作怪。 每当你将⼀个变量赋值为另⼀个可 变类型的变量时, 对这个数据的任意改动会同时反映到这两个变量上去。 新变量只不过是 ⽼变量的⼀个别名⽽已。 这个情况只是针对可变数据类型。 下⾯的函数和可变数据类型让 你⼀下就明⽩了: def add_to(num, target=[]): target.append(num) return target add_to(1) # Output: [1] add_to(2) # Output: [1, 2] add_to(3) # Output: [1, 2, 3] Python 进阶 对象变动 Mutation 51 你可能预期它表现的不是这样⼦。 你可能希望, 当你调⽤add_to 时, 有⼀个新的列表被 创建, 就像这样: def add_to(num, target=[]): target.append(num) return target add_to(1) # Output: [1] add_to(2) # Output: [2] add_to(3) # Output: [3] 啊哈!这次又没有达到预期, 是列表的可变性在作怪。 在 Python 中当函数被定义时, 默认 参数只会运算⼀次, ⽽不是每次被调⽤时都会重新运算。 你应该永远不要定义可变类型的 默认参数, 除⾮你知道你正在做什么。 你应该像这样做: def add_to(element, target=None): if target is None: target = [] target.append(element) return target 现在每当你在调⽤这个函数不传⼊target 参数的时候, ⼀个新的列表会被创建。 举个例 ⼦: add_to(42) # Output: [42] add_to(42) # Output: [42] add_to(42) # Output: [42] |