PYTHON函数对列表修改产生了奇怪的问题

我有一个函数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]也发生了改变。

  • 以下回答由chatgpt基于相关博客总结生成:

    问题原因是在Python中,列表是可变对象,而函数参数是对象的引用。在函数内部对列表进行修改时,其实是在修改原来列表的内容。因此,第二次调用函数时,会导致修改前后的列表完全相同。

    解决方法可以使用切片或者拷贝技术来创建一个新的列表,而不是直接修改原来的列表。具体的步骤如下:

    1. 使用切片操作或copy()方法创建原列表的副本:
    new_list = original_list[:]
    # 或者
    import copy
    new_list = copy.copy(original_list)
    
    1. 调用change()函数时将副本作为参数传入:
    change(new_list)
    
    1. 在change()函数内部对副本进行修改,而不是原列表:
    def change(lst):
        # 修改副本lst
        # ...
    

    通过这种方式,每次调用函数时都会操作一个新的列表,不再影响原来的列表。