Python中对象的复制有赋值与拷贝,最近刚好遇到一个关于赋值与拷贝的bug,于是研究了一番。
赋值
和c++不同,python中对象的赋值就是对象的引用,没有为新的对象开辟内存空间,如
A = ['alpha','beta','Charlie','delta']
B = A
将对象A赋值给对象B,实际上是新增一个指针B,将指针B指向对象A的地址。也就是说,A和B指向的是同一片内存空间,内存中没有为B开辟新的空间,B只是A的别名。
在这种情况下,修改了A,就是修改了B。同理,修改了B,就是修改了A。
拷贝
拷贝与赋值不同,会为新的对象开辟新的内存空间。
拷贝有两种,浅拷贝和深拷贝
浅拷贝(shallow copy)
浅拷贝有三种:切片操作,工厂函数,copy模块的copy函数切片操作:B = A[:],或者B = [each for each in A]
工厂函数:B = list(A)
copy函数:B = copy.copy(A)
浅拷贝创建了新的对象,其对象的内容是原对象的引用。浅拷贝之所以称为浅拷贝,就是因为此。无论A还是B,两者包含的元素地址是相同的。
当A的元素中嵌套了list时,改变了A中嵌套的list,B也会发生变化。这是因为,B存放的是A的内容的引用,修改A非嵌套list元素,会修改这个元素的引用,会指向别的位置,此时B的元素还是指向原来地址,因此B中的元素不变。修改A中嵌套list的元素,嵌套list的首地址并没有变化,无论A和B,指向的都是list首地址,此时A和B都会发生变化。
为此,需要深拷贝
深拷贝(deep copy)
B = copy.deepcopy(A)
拷贝了包括多层嵌套在内的所有元素。这时B就是一个全新的对象,与A没有任何关系,无论修改AB,二者互不影响。