我最近遇到了切片的问题.检查以下代码:
def clean(l):
for i in range(len(l)):
l[i] = 0
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
clean(lst[:])
print lst
Run Code Online (Sandbox Code Playgroud)
这个代码打印出来[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
似乎l[i] = 0函数内部没有任何效果.所以我猜Python在将一个切片传递给函数时正在制作列表的副本...然后我做了另一个测试......
def clean(l):
for i in range(len(l)):
print id(l[i])
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
clean(lst)
print
clean(lst[:])
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是输出结果如下:
140373225703016
140373225702992
140373225702968
140373225702944
140373225702920
140373225702896
140373225702872
140373225702848
140373225702824
140373225702800
140373225703016
140373225702992
140373225702968
140373225702944
140373225702920
140373225702896
140373225702872
140373225702848
140373225702824
140373225702800
Run Code Online (Sandbox Code Playgroud)
这说明Python并没有制作列表的副本,而是制作引用的副本......这变得很奇怪.由于函数内部的引用仍然指向原始列表对象,为什么将值设置为0无效?
切片在应用于列表时返回一个新容器,但内部项仍然相同.在0切片列表上分配索引时,您将更改该新容器的值而不是原始列表.
>>> lis = [1, 2, 3]
>>> lis_1 = lis[:]
>>> lis_1 is lis # Outer lists are different
False
>>> lis_1[0] is lis[0]
True
>>> lis_1[0] = 10 # This assignment affects only `lis_1` not `lis`.
>>> lis
[1, 2, 3]
>>> lis_1
[10, 2, 3]
>>>
Run Code Online (Sandbox Code Playgroud)
以上列表仅包含不可变项目,当您的列表包含可变项目并且您对该项目执行就地操作时,可以在所有列表中看到更改:
>>> lis = [[1], 2, 3]
>>> lis_1 = lis[:]
>>> lis_1 is lis #Outer container are different
False
>>> lis[0] is lis_1[0] #But inner lists are same.
True
>>> lis[0].append(10)
>>> lis
[[1, 10], 2, 3]
>>> lis_1
[[1, 10], 2, 3]
Run Code Online (Sandbox Code Playgroud)
来自docs:
一些对象包含对其他对象的引用; 这些被称为 容器.容器的例子是
tuples,lists和dictionaries.引用是容器值的一部分.在大多数情况下,当我们谈论容器的价值时,我们暗示的是价值,而不是所包含对象的身份; 但是,当我们谈论容器的可变性时,只隐含了直接包含的对象的标识.因此,如果不可变容器(如元组)包含对可变对象的引用,则如果更改了可变对象,则其值会更改.