与传入普通变量不同,当在python的函数参数中传入列表时,传入的是列表的引用,也就是说,如果在函数内部改变了传入的列表,则当函数调用后,该列表也随之改变了。举个栗子:
定义一个参数为列表的函数:
def f(x):
x.append(1)
return x
调用该函数:
>>> x = [1,2]
>>> f(x)
[1, 2, 3]
>>> x
[1, 2, 3]
可知在函数调用完成后,传入的列表x也随之改变了。如果我们不想让函数调用后改变x的值,可以用拷贝功能。
1.列表的拷贝与引用
在python3中,可以用列表的copy方法或索引全部元素来完成拷贝;而在python2中,只能用索引全部元素来完成拷贝。
>>> testList = [1,2,3]
>>> check1 = testList #把列表的引用赋给check1
>>> check2 = testList[:] #把列表的拷贝赋给check2
>>> testList.append(4) #改变原列表
>>> print(check1, check2) #可知check1改变了,而check2不受影响
[1, 2, 3, 4] [1, 2, 3]
注:在python3中,除了像上面代码中那样引用,还能通过列表的copy方法来引用,即:
check3 = testList.copy()
可用下图来表示拷贝和引用的原理:
我们定义了一个列表[1,2,3],起名叫testList。列表的引用就是给它再起个名字叫做check1,虽然名字不一样,但指向的都是同一个变量,在内存中都是同一个位置。
拷贝就是在内存中另一个位置拷贝此列表,起名叫check2。虽然两个变量的值都是[1,2,3],但它们的地址却是不同的。
除了列表,字典、集合和numpy库中的matrix、array数据结构都有拷贝和引用。与python3中的列表类型,它们也都有copy方法。
2.字典的拷贝与引用
>>> testDict = {'age':20, 'name':'Tom'}
>>> check1 = testDict #赋值testDict的引用
>>> check2 = testDict.copy() #赋值testDict的拷贝
>>> testDict['age'] = 30
>>> print(check1, check2)
{'age': 30, 'name': 'Tom'} {'age': 20, 'name': 'Tom'}
3.集合的拷贝与引用
>>> testSet = set([1,2])
>>> check1 = testSet #赋值testSet 的引用
>>> check2 = testSet.copy() #赋值testSet 的拷贝
>>> testSet.add(3)
>>> print(check1, check2)
(set([1, 2, 3]), set([1, 2]))
4.array的拷贝与引用
>>> from numpy import *
>>> testArray = array([[1,2],[3,4]])
>>> check1 = testArray #赋值testArray 的引用
>>> check2 = testArray.copy() #赋值testArray 的拷贝
>>> testArray[0,0] = 100
>>> print check1
[[100 2]
[ 3 4]]
>>> print(check2)
[[1 2]
[3 4]]
5.matrix的拷贝与引用
拷贝与引用的用法与array相同。