我们今天的话题要从“可变对象的原处修改”这里引入,这是一个值得注意的问题。
上一集里我们谈到,赋值操作总是存储对象的引用,而不是这些对象的拷贝。由于在这个过程中赋值操作会产生相同对象的多个引用,因此我们需要意识到“可变对象”在这里可能存在的问题:在原处修改可变对象可能会影响程序中其他引用该对象的变量。如果你不想看到这种情景,则你需要明确的拷贝一个对象,而不是简单赋值。
X = [1,2,3,4,5]
L = ['a', X, 'b']
D = {'x':X, 'y':2}
print(L)
print(D)
['a', [1, 2, 3, 4, 5], 'b']
{'y': 2, 'x': [1, 2, 3, 4, 5]}
在这个例子中,我们可以看到列表[1,2,3,4,5]有三个引用,被变量X引用、被列表L内部元素引用、被字典D内部元素引用。那么利用这三个引用中的任意一个去修改列表[1,2,3,4,5],也会同时改变另外两个引用的对象,例如我利用L来改变[1,2,3,4,5]的第二个元素,运行的结果就非常明显。
X = [1,2,3,4,5]
L = ['a', X, 'b']
D = {'x':X, 'y':2}
L[1][2] = 'changed'
print(X)
print(L)
print(D)
[1, 2, 'changed', 4, 5]
['a', [1, 2, 'changed', 4, 5], 'b']
{'x': [1, 2, 'changed', 4, 5], 'y': 2}
【妹子说】有坑请绕行呀,在这些地方还真的挺容易犯错的。
引用是其他语言中指针的更高层的模拟。他可以帮助你在程序范围内任何地方传递大型对象而不必在途中产生拷贝,起到优化程序的作用。
【妹子说】可是如果我不想共享对象引用,而是想实实在在获取对象的一份独立的复制,该怎么办呢?
能想到这一层确实很不错,其实这个很简单,常用的手法有以下几种:
第一种方法:分片表达式能返回一个新的对象拷贝,没有限制条件的分片表达式能够完全复制列表