Python中的赋值(复制)、浅拷贝与深拷贝

https://zhuanlan.zhihu.com/p/54011712

首先需要了解下几个概念

  • 变量:是一个系统表的元素,拥有指向对象的连接空间
  • 对象:被分配的一块内存,存储其所代表的值
  • 引用:是自动形成的从变量到对象的指针
  • 类型:属于对象,而非变量
  • 不可变对象:一旦创建就不可修改的对象,包括字符串、元组、数值类型

(该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。)

  • 可变对象:可以修改的对象,包括列表、字典、集合

(该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的地址,通俗点说就是原地改变。)

当我们写:

a = ‘python‘

Python解释器干的事情:

1. 创建也变量a

2. 创建一个对象(分配一块内存),来存储值 ‘python‘

3. 将变量与对象,通过指针连接起来,从变量到对象的连接称之为引用(变量引用对象)



1.赋值: 只是复制了新对象的引用,不会开辟新的内存空间。

并不会产生一个独立的对象单独存在,只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。

2.浅拷贝: 创建新对象,其内容是原对象的引用。

浅拷贝有三种形式: 切片操作,工厂函数,copy模块中的copy函数。

如: lst = [1,2,[3,4]]

切片操作:lst1 = lst[:] 或者 lst1 = [each for each in lst]

工厂函数:lst1 = list(lst)

copy函数:lst1 = copy.copy(lst)

浅拷贝之所以称为浅拷贝,是它仅仅只拷贝了一层,拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已,在lst中有一个嵌套的list[3,4],如果我们修改了它,情况就不一样了。

浅复制要分两种情况进行讨论:

1)当浅复制的值是不可变对象(字符串、元组、数值类型)时和“赋值”的情况一样,对象的id值(id()函数用于获取对象的内存地址)与浅复制原来的值相同。

2)当浅复制的值是可变对象(列表、字典、集合)时会产生一个“不是那么独立的对象”存在。有两种情况:

第一种情况:复制的对象中无复杂子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。

第二种情况:复制的对象中有复杂子对象(例如列表中的一个子元素是一个列表),如果不改变其中复杂子对象,浅复制的值改变并不会影响原来的值。 但是改变原来的值中的复杂子对象的值会影响浅复制的值。

3.深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。

所以改变原有被复制对象不会对已经复制出来的新对象产生影响。

只有一种形式,copy模块中的deepcopy函数

对于不可变对象的深浅拷贝

import copy
a=(1,2,3)

print("=====赋值=====")
b=a
print(a)
print(b)
print(id(a))
print(id(b))

print("=====浅拷贝=====")
b=copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))

print("=====深拷贝=====")
b=copy.deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))

结果:

=====赋值=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128
=====浅拷贝=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128
=====深拷贝=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128

不可变对象类型,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。

一句话就是,不可变类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。

对于可变对象深浅拷贝

import copy
a=[1,2,3]

print("=====赋值=====")
b=a
print(a)
print(b)
print(id(a))
print(id(b))

print("=====浅拷贝=====")
b=copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))

print("=====深拷贝=====")
b=copy.deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))

结果:

=====赋值=====
[1, 2, 3]
[1, 2, 3]
37235144
37235144
=====浅拷贝=====
[1, 2, 3]
[1, 2, 3]
37235144
37191432
=====深拷贝=====
[1, 2, 3]
[1, 2, 3]
37235144
37210184

赋值: 值相等,地址相等

copy浅拷贝:值相等,地址不相等

deepcopy深拷贝:值相等,地址不相等

对于可变对象深浅拷贝(外层改变元素)

import copy
l=[1,2,3,[4, 5]]

l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l.append(6)

print(l)
print(l1)
print(l2)
print(l3)

结果:

[1, 2, 3, [4, 5], 6]     #l添加一个元素6
[1, 2, 3, [4, 5], 6]     #l1跟着添加一个元素6
[1, 2, 3, [4, 5]]        #l2保持不变
[1, 2, 3, [4, 5]]        #l3保持不变

对于可变对象深浅拷贝(内层改变元素)

import copy
l=[1,2,3,[4, 5]]

l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l[3].append(6) 

print(l)
print(l1)
print(l2)
print(l3)

结果:

[1, 2, 3, [4, 5, 6]]      #l[3]添加一个元素6
[1, 2, 3, [4, 5, 6]]      #l1跟着添加一个元素6
[1, 2, 3, [4, 5, 6]]      #l2跟着添加一个元素6
[1, 2, 3, [4, 5]]         #l3保持不变

1.外层添加元素时,浅拷贝不会随原列表变化而变化;内层添加元素时,浅拷贝才会变化。
2.无论原列表如何变化,深拷贝都保持不变。
3.赋值对象随着原列表一起变化。

原文地址:https://www.cnblogs.com/zy09/p/11855706.html

时间: 2024-10-09 05:11:15

Python中的赋值(复制)、浅拷贝与深拷贝的相关文章

python中关于赋值、浅拷贝与深拷贝的问题

Python中关于对象复制有三种类型的使用方式,赋值.浅拷贝与深拷贝.他们既有区别又有联系,刚好最近碰到这一类的问题,研究下. 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不同.如下: list_a = [1,2,3,"hello",["python","C++"]] list_b = list_a 这种情况下,list_b和list_a是一样的,他们指向同一片内存,list_b不过是list_a的别名,是引用. 我们可

Python中的赋值、浅拷贝、深拷贝

在理解浅拷贝和深拷贝之前,首先要理解学习一下变量在Python中是怎样存储的: 变量的类型是分值引用与地址引用两种. python的一切变量都是对象,变量的存储,采用了地址引用的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身. 在Python中,是有多种数据类型:bool.int.long.float.string.list.dict.tuple.set; 其中可分为基本数据类型和复杂数据结构: 基本数据类型:bool.int.long.float.string; 复杂数据结

python中的赋值、浅拷贝和深拷贝

1.对于不可变数据类型来说,没有深浅拷贝之分,这些操作都是将变量指向同一个地址空间,两者的id一样,如果对其重新赋值,也只是重新创建了一个对象,替换掉旧的. 2.对于可变数据类型来说 2.1 赋值 两者完全指向相同的地址空间id()一样,可变数据类型的改变会导致两者都改变. a = [1,2,3,4,[33,44,55]] c = a print(id(a),id(c)) print(a,c) a[0]="改变" print(a,c) 结果 2352692648520 23526926

Python中的对象引用、浅拷贝与深拷贝

最近项目中遇到一个Python浅拷贝机制引起的bug,由于对于Python中对象引用.赋值.浅拷贝/深拷贝机制没有足够的认识,导致调试了很久才发现问题,这里简单记录一下相关概念. 在Python的设计哲学中,Python中的每一个东西都是对象,都有一个ob_refcnt变量,这个变量维护着对对象的引用计数,决定着对象的创建与消亡. 所以在Python程序中,一般的赋值操作其实只是将左值指向了右值的引用,并不会创建新的对象,可以通过id函数查看Python中对象在内存中的唯一标识,以list对象为

Python中赋值、浅拷贝与深拷贝

python中关于对象复制有三种类型的使用方式,赋值.浅拷贝与深拷贝.他们既有区别又有联系,刚好最近碰到这一类的问题,研究下. 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不同.如下: list_a = [1,2,3,"hello",["python","C++"]] list_b = list_a 这种情况下,list_b和list_a是一样的,他们指向同一片内存,list_b不过是list_a的别名,是引用. 我们可

关于python中赋值、浅拷贝、深拷贝之间区别的深入分析

大家都知道,在python中复制一个对象有多种方法,其中常用的是赋值.浅拷贝和深拷贝,这三者之间有哪些区别和哪些坑呢? 首先,定义一下: 赋值:  a =1    b =a    a赋值给了b 浅拷贝: a = []  b = a.copy() 或者import copy             b = copy.copy(a) 深拷贝:import copy  a = []   b = copy.deepcopy(a) 未完待续

Python中的赋值、深拷贝与浅拷贝(内存地址)

1.python中的可变对象与不可变对象 (1) 可变对象:dict,list def dict_test(): a = {} b = a print(id(a)) # 140367329543360 a['a'] = 'hhhh' print('id a:' + str(id(a))) # id a:140367329543360 print('a:' + str(a)) # a:{'a': 'hhhh'} print('id b:' + str(id(b))) # id b:14036732

Python——赋值、浅拷贝、深拷贝

和很多语言一样,Python中也分为简单赋值.浅拷贝.深拷贝这几种“拷贝”方式. 在学习过程中,一开始对浅拷贝理解很模糊.不过经过一系列的实验后,我发现对这三者的概念有了进一步的了解. 一.赋值 赋值算是这三种操作中最常见的了,我们通过一些例子来分析下赋值操作: str例 >>> a = 'hello' >>> b = 'hello' >>> c = a >>> [id(x) for x in a,b,c] [4404120000,

Python 赋值、浅拷贝和深拷贝

初学Python,和C++还是有许多不同.直接赋值.浅拷贝和深拷贝,这三种拷贝对象的操作之间还是有许多的区别.Python语言的版本为2.7,在Pycharm中进行实验. 一.直接赋值 用下面的代码来实验: 1 origin = [1, "string", [1, 3, 5]] 2 Copy = origin 3 print Copy 4 print id(origin), id(Copy) 5 Copy[0] = 5 6 print origin, Copy 7 Copy[1] =