标签:列表 包括 运算 src size als 对象引用 元组 idt
首先,简单理解一下概念:(注意:以下概念都是建立在可变数据类型上,包括列表list和字典dict)
1、直接赋值:当创建一个对象a,然后把它赋给另一个变量b的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用;原始列表改变,被赋值的b也会做相同的改变;
2、copy浅拷贝,只拷贝了父对象,没有拷贝子对象,所以原始数据的子对象的改变,浅拷贝的子对象也会改变;但是父对象的改变,浅拷贝的父对象不会改变;
3、深拷贝,包含父对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变;
接下来我们来跑一个代码例子,原始对象包含子对象的例子
import copy# 列表型,即可变数据类型,但不包含子对象
a=[1,2]
b=copy.deepcopy(a)
c=a
d=copy.copy(a)
e=[1,2]
print(b is a)
print(c is a)
print(d is a)
print(e is a)
print("变化前:",a,b,c,d,e,"\n")
a.append(5)
print("变化后:",a,b,c,d,e,"\n")
输出结果:
False
True
False
False
变化前: [1, 2] [1, 2] [1, 2] [1, 2] [1, 2]
变化后: [1, 2, 5] [1, 2] [1, 2, 5] [1, 2] [1, 2]
分析:
1、我们创建一个列表型数据a,即可变数据类型,但不包含子对象;
PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象
x is y
, 类似 id(x) == id(y)
, 如果引用的是同一个对象则返回 True,否则返回 False
2、b深拷贝a,与a不是引用自一个对象,所以输出false
3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true
4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false
5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false
6、a对象增加值5,只有直接赋值的c的值同步发生了改变,因为深拷贝和浅拷贝的父对象和原始对象都是不一样的了(可以回头看看概念和图例),而e对象本来就是与a无关的,所以更加不会发生变化。
我们再跑一个代码例子,原始对象包含子对象的例子
import copy
# 列表型,即不可变数据类型,但包含子对象
a=[1,2,[11,22]]
b=copy.deepcopy(a)
c=a
d=copy.copy(a)
e=[1,2,[11,22]]
print(b is a)
print(c is a)
print(d is a)
print(e is a)
print("变化前:",a,b,c,d,e,"\n")
a[2].append(33)
print("变化后:",a,b,c,d,e,"\n")
输出结果:
False
True
False
False
变化前: [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]] [1, 2, [11, 22]]
变化后: [1, 2, [11, 22, 33]] [1, 2, [11, 22]] [1, 2, [11, 22, 33]] [1, 2, [11, 22, 33]] [1, 2, [11, 22]]
分析:
1、我们创建一个列表型数据a,即可变数据类型,且包含子对象,子对象也是个列表;
PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象
x is y
, 类似 id(x) == id(y)
, 如果引用的是同一个对象则返回 True,否则返回 False
2、b深拷贝a,与a不是引用自一个对象,所以输出false
3、c是a直接赋值的,拷贝了a的引用,即与a引用自同一个对象,所以输出true
4、d浅拷贝a,与a也不是引用自同一个对象,所以输出false
5、e虽然和a值一样,但属于不同的对象,在内存中有不一样的地址,所以输出false
6、a对象的子对象列表增加值33,除了直接赋值的c的值同步发生了改变,浅拷贝的子对象也发生了改变,因为浅拷贝的子对象和原始对象中的子对象引用的是同一个对象!(可以回头看看概念和图例),而e对象本来就是与a无关的,所以依然不会发生变化。
最后,我们来思考一个问题,如果是不可变数据类型,结果是什么?
import copy
# 数值型,即不可变数据类型
a=1
b=copy.deepcopy(a)
c=a
d=copy.copy(a)
e=1
print(b is a)
print(c is a)
print(d is a)
print(e is a)
print("变化前:",a,b,c,d,e,"\n")
a=2
print("变化后:",a,b,c,d,e,"\n")
输出结果:
True
True
True
True
变化前: 1 1 1 1 1
变化后: 2 1 1 1 1
分析:
1、我们创建一个数值型数据a,即不可变数据类型;
PS:我们使用身份运算符is,判断两个标识符是不是引用自一个对象
x is y
, 类似 id(x) == id(y)
, 如果引用的是同一个对象则返回 True,否则返回 False
2、结果发现无论是深拷贝、浅拷贝、直接赋值还是新建一个数值一样的变量,在内存中的地址都是一样的,身份运算输出都是true。这是因为:不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址)!
6、所以当a变量的值改变之后,其他的变量都不会改变,因为是a引用的对象变了,而其他变量的引用并没有发生改变,依然引用“数值1”这个对象。
由此可见,对于不可变数据类型(数值型、字符串型和元组),拷贝都是无差别的。
标签:列表 包括 运算 src size als 对象引用 元组 idt
原文地址:https://www.cnblogs.com/cyanlee/p/12296044.html