曾经看到这样个问题 个字典中的元素是列表 将这个列表元素赋值给个变量 然后修改这个列表中元素的值 结果发现 字典中那个列表也同样修改了。那个问题如下:

dict = {'a':[1,2,3,4,5],'b':2}x = dict['a']for i in range(5):  x[i] = 0print(dict['a'])

程序结果 如下: [0, 0, 0, 0, 0]

这儿涉及到Python赋值到底是引用还是拷贝一份的问题 即赋值时是传值还是传址。上面问题是将"a"的值赋给了x出现了上述情况 如果是将"b"的值赋给了x 当 修改x的值时 字典dict的值并不受影响。

>>> dict = {'a':[1,2,3,4,5],'b':2}>>> x = dict['b']>>> x2>>> x=x+3>>> x5>>> dict{'a': [1, 2, 3, 4, 5], 'b': 2}>>>

那么问题来了 变量赋值传递时什么情况下是传值(拷贝) 什么情况下是传址(引用)呢?

1、直接拷贝

当 不知道是引用还是拷贝的情况下 可以显式的拷贝。如字典对象本身都具有拷贝的方法:

x=dict.copy()

没有拷贝方法的对象 也是可以拷贝的。这儿 引入个深拷贝的概念 深拷贝——即python的copy模块提供的个deepcopy方法。深拷贝会完全复制原变量相关的所有数据 在内存中生成一套完全一样的内容 在这个过程中 对这两个变量中的个进行任意修改都不会影响其 变量。还是上面的代码 如果改成如下:

import copydict = {'a':[1,2,3,4,5],'b':2}x = copy.deepcopy(dict['a'])for i in range(5):  x[i] = 0print(dict['a'])

结果 dict值不受影响。

除了深拷贝 copy模块还提供个copy方法 称其为浅拷贝 对于简单的对象 深浅拷贝都是一样的 上面的词典对象的copy方法就是浅拷贝。

>>> dict{'a': [8, 2, 3, 4, 5], 'b': 4}>>> dd=copy.copy(dict)>>> dd{'a': [8, 2, 3, 4, 5], 'b': 4}>>> dd['a'][0]=7>>> dd{'a': [7, 2, 3, 4, 5], 'b': 4}>>> dict{'a': [7, 2, 3, 4, 5], 'b': 4}>>> ee=dict.copy()>>> ee{'a': [7, 2, 3, 4, 5], 'b': 4}>>> ee['a'][0]=9>>> ee{'a': [9, 2, 3, 4, 5], 'b': 4}>>> dict{'a': [9, 2, 3, 4, 5], 'b': 4}>>> ee['b']=5>>> ee{'a': [9, 2, 3, 4, 5], 'b': 5}>>> dict{'a': [9, 2, 3, 4, 5], 'b': 4}>>>

浅拷贝时改变第一层次相互不受影响(上例中词典b值的修改) 第二层次(上例中词典a的列表值修改)就相互影响了 改个 其 跟着变。看看id吧:

>>> id(dict)20109472>>> id(dd)20244496>>> id(ee)20495072>>> id(dd['a'])20272112>>> id(ee['a'])20272112>>> id(dict['a'])20272112>>>

可见词典各个拷贝的id是不同的 但词典a值的id是相同的。如果 需要真正意义的拷贝 就用深拷贝吧。

2、传递规则

Python 赋值过程中不明确区分拷贝和引用 一般对静态变量的传递为拷贝 对动态变量的传递为引用。(注 对静态变量首次传递时也是引用 当需要修改静态变量时 因为静态变量不能改变 所以需要生成个新的空间存储数据)。

  • 字符串 数值 元组均为静态变量
  • 列表 字典为动态变量。

变量有时比较复杂 存在组合现象 如字典中包含列表 列表中包含字典 但赋值时 总是属于某个类型。如果实在不清楚状况 可以试验一下 用id()这个函数看看 如果是引用 两个变量指向的地址是相同的。例如:

>>> a=6>>> id(a)10413476>>> b=a>>> id(b)10413476>>> b=8>>> id(b)10413452>>>

修改变量b之前 a和b指向的地址是相同的 修改b后 地址就变了。

原文链接:https://blog.csdn.net/iamlaosong/article/details/77505510