python系列教程127——引用VS拷贝

朋友们,如需转载请标明出处:blog.csdn.net/jiangjunsho…

声明:在人工智能技术教学期间,不少学生向我提一些python相关的问题,所以为了让同学们掌握更多扩展知识更好地理解AI技术,我让助理负责分享这套python系列教程,希望能帮到大家!由于这套python教程不是由我所写,所以不如我的AI技术教学风趣幽默,学起来比较枯燥;但它的知识点还是讲到位的了,也值得阅读!PS:看不懂本篇文章的同学请先看前面的文章,循序渐进每天学一点就不会觉得难了!

我们曾经提到过,赋值操作是储存对象的引用,而不是这些对象的拷贝。因为赋值操作会产生一个对象的多个引用,修改对象时可能会影响程序中其他地方对该对象的其他引用。如果你不想一改全改,那么就需要明确地告诉Python复制该对象,而不是简单地进行赋值操作。

例如,下面这个例子创建了一个列表X,以及另一个列表L,L嵌套对列表X的引用。另外还创建了一个字典D,含有另一个对列表X的引用。

>>> X = [1,2,3]

>>> L = ['a',X,'b']  # Embed references to X's object

>>> D = {'x':X,'y':2}
复制代码

在上面的代码中,对同一个对象列表就有三个引用:X、L的第二个元素以及D的第一个元素。

因为变量X引用的列表也在被L和D内引用,由于列表是可变的,修改这三个引用中任意一个列表对象,也会同时改变另外两个引用的对象。

>>> X[1] = 'surprise'  # Changes all three references!

>>> L

['a',[1,'surprise',3],'b']

>>> D

{'x': [1,'surprise',3],'y': 2}
复制代码

大多数情况下,引用的这种特性是对我们有利的,因为你可以在程序范围内任何地方传递大型对象而不必在途中产生拷贝,这样一来,既可以节约内存又可以提升运行速度。然而,如果你不想要这种一改全改的特性,那么就你需要明确地进行复制拷贝操作。

•没有限制条件的分片表达式(L[:])能够复制序列。 •字典copy方法(X.copy())能够复制字典。 •有些内置函数(例如,list)也能够生成拷贝(list(L))。

举个例子,假如有一个列表和一个字典,你不想通过其他变量引用来修改它们的值。

>>> L = [1,2,3]

>>> D = {'a':1,'b':2}
复制代码

你可以把拷贝赋值给其他变量,而不是进行引用复制。

>>> A = L[:]     # Instead of A = L (or list(L))

>>> B = D.copy()  # Instead of B = D (ditto for sets)
复制代码

这样一来,由其他变量产生的改变只会修改拷贝,而不是原对象。

>>> A[1] = 'Ni'

>>> B['c'] = 'spam'

>>>

>>> L,D

([1,2,3],{'a': 1,'b': 2})

>>> A,B

([1,'Ni',3],{'a': 1,'c': 'spam','b': 2})
复制代码

对于文章开头处那个例子而言,你可以通过对原始列表进行分片操作来避免引用。

>>> X = [1,2,3]

>>> L = ['a',X[:],'b']   # Embed copies of X's object

>>> D = {'x':X[:],'y':2}
复制代码

L和D现在会指向不同的列表而不是X。这样一来,通过X所做的修改只能够影响X而不会再影响L和D。类似地,修改L或D也不会影响X。

需要注意的是:无条件值的分片以及字典copy方法只能做顶层复制。也就是说,不能够复制嵌套的数据结构。如果你需要将一个深层嵌套的数据结构进行完整的拷贝,那么就要使用标准的copy模块——先import copy,然后执行X = copy.deepcopy(Y)来对任意嵌套的对象Y做完整的复制。这一调用语句能够递归地遍历对象来复制它们所有的组成部分。

Guess you like

Origin juejin.im/post/7032190723076128775