本节介绍一个重要概念——引用。为了便于说明这个概念,我们先从两个简单的例子来入手。
引用
例子1
>>> name1 = 'mike'
>>> name2 = name1 # 此时name2为'mike'
>>> name1 = 'jack'
>>> name2
'mike'
在上面一段代码中,我们首先给name1赋值'mike',然后再让name2等于name1。接下来我们改变name1的值为'jack',此时name2的值并没有随着name1变为'jack',name2仍然为'mike'。
现在我们把name1改为列表,再次进行上述的步骤。
例子2
>>> name1 = ['mike', 'jack']
>>> name2 = name1
>>> name1.append('lucy')
>>> name1
['mike', 'jack', 'lucy']
>>> name2
['mike', 'jack', 'lucy']
从上面的代码可以看出,当name1为列表的时候,我们修改name1的时候name2也被修改了。这究竟是怎么回事呢?
在入门篇第一节中,我们介绍变量的时候曾把变量在计算机中存储的形式比作在一个“盒子”里装入信息。这个“盒子”是在计算机内存中开辟出的一块空间,“盒子”里装入的是变量的值。例子1的过程可以用下图表示。
在第一步中name1被赋值'mike'。在第二步中执行name2=name1。在第三步中执行name1='jack'。从上图中可以看出,name1和name2分别把自己的值保存在两个不同的盒子里,因此name1修改自己的值并不会影响name2的值。
可是在例子2中,当name1变为列表的时候,这个过程变为了如下的形式。
在第一步中name1被赋值['mike', 'jack']。在第二步中执行name2=name1,注意此时并没有创建一个新“盒子”,而是name2直接指向了name1的“盒子”,相当于这个“盒子”现在有两个名字name1和name2。因此在第三步执行name1.append('lucy')后,name2也被修改了,因为name1和name2对应的是同一个“盒子”。
在例子2中,我们执行name1=name2语句的时候,实际上是将列表name1的“引用”传递给了name2。因此,之后我们在使用赋值操作符=的时候,一定要注意是拷贝了新值还是传递了引用。一般来说,对于不可变的数据类型如字符串、整型、元组,python 变量会保存值本身。而对于可变数据类型如列表、字典,python会使用引用。
copy()和deepcopy()
有时候我们想拷贝一个新的列表并修改其中的内容,同时保留原来的列表不变。此时显然是不能使用引用的,那么该如何操作呢?copy()和deepcopy()函数提供了解决方案。
copy模块中的copy()函数会创建一个新的“盒子”,然后把原来的列表中的值拷贝一份到新“盒子”中。使用方法如下所示,使用copy()函数后,修改name1的时候name2没有受到影响。
>>> import copy
>>> name1 = ['mike', 'jack']
>>> name2 = copy.copy(name1)
>>> name1.append('lucy')
>>> name1
['mike', 'jack', 'lucy']
>>> name2
['mike', 'jack']
deepcopy()使用方法与copy()一样。如果要拷贝的列表中还包含了列表,那么此时需要使用deepcopy()来代替。