我有一个函数change(),我想要它对一个列表进行修改,并输出原列表和新列表,但我发现了很奇怪的问题:
求指点,为什么第二次代码,新旧列表会一样
def change(old):
new = old[:]
print(old)
new[1] = 22
#当我对列表的一号索引修改值后,一切正常
print("-------")
print(old)
print(new)
aa = [[5, 2], ['AAA']]
change(aa)
def change(old):
new = old[:]
print(old)
#当我对列表的0号索引的一号索引修改值后,新旧列表变成相同的了
new[0][1] = 33
print("-------")
print(old)
print(new)
aa = [[5, 2], ['AAA']]
change(aa)
new = old[:]
这个导致复制了一份,之后new就和old无关了,修改new自然不会作用到old上
new = old[:]
表示new是old的一个拷贝,如果old本身是个一维list,那么修改new的元素将不会改变old的元素
但是第二段代码中,old是个二维list,虽然new是old的拷贝,但是里面的元素本身还是可变值类型,指向的是同一个引用
你可以打印id(new),id(old),id(new[0]),id(old[0])对比看看
-=-=-=-=
其实很好理解,本质上new=old[:]就是做了这样一个操作
new=[]
for x in old:
new.append(x)
如果x是不可变值类型,比如int,那么修改new里的int当然不会对old里的int产生任何影响
但是如果x本身是list,那么修改new里的x中的元素,跟修改old里的x中的元素是一回事,因为x始终是同一个x
除非你修改x本身,new[0]=[1,2,3]这样,new和old就不一样了
如果你需要多维嵌套list整个和原来的没有关系,仅仅是值拷贝过来,可以搜索深拷贝
只需要了解
old = [[0, 3], '1000']
new = old[:]
print(old is new)
# False
print(old[0] is new[0])
# True
这句代码的含义是,在内存中新分配了一个地址,此时new和old指向的已经不为一个对象。
这也是为什么你第一段代码中,更改new[1]的值时,old没有随之改变的原因。
至于第二段代码,前面同理,但是问题出在new[0]和old[0]上,它们是同一个对象,指向的是同一个内存地址。所以你改变new[0][1]时,old[0][1]也发生了改变。
问题原因是在Python中,列表是可变对象,而函数参数是对象的引用。在函数内部对列表进行修改时,其实是在修改原来列表的内容。因此,第二次调用函数时,会导致修改前后的列表完全相同。
解决方法可以使用切片或者拷贝技术来创建一个新的列表,而不是直接修改原来的列表。具体的步骤如下:
new_list = original_list[:]
# 或者
import copy
new_list = copy.copy(original_list)
change(new_list)
def change(lst):
# 修改副本lst
# ...
通过这种方式,每次调用函数时都会操作一个新的列表,不再影响原来的列表。