首页 > 编程语言 >python 深拷贝和浅拷贝

python 深拷贝和浅拷贝

时间:2023-02-03 18:56:43浏览次数:31  
标签:python list list1 print 拷贝 copy id

python 深拷贝和浅拷贝

变量: 存储对象的引用

对象:会分配一块内存空间,存储实际数据

引用:变量指向对象,理解为指针

变量存储在栈内存,对象存储在堆内存。

Python数据类型分为可变数据类型和不可变数据类型。

  • 可变数据类型包括:List(列表)、Dictionary(字典)、Set(集合)
  • 不可变数据类型包括:String(字符串)、Number(数字)、Tuple(元组)

赋值

Python 的赋值语句并不是创建一个新对象,只是创建了一个共享原始对象引用的新变量

不可变对象的赋值

a = 1
b = a

print(a, b)

a += 2
print(a, b)

print("a id:", id(a))
print("b id:", id(b))

# 输出结果
1 1
3 1
a id: 4564097808
b id: 4564097776
  • 修改变量 a 的值,不会同步修改变量 b 的值
  • 因为赋值操作 a += 2 后,变量 a 存储的对象引用已经改变了

可变对象的赋值

当其中一个内数据改变后,另一个也改变了

a = [1, 2, 3]
b = a

print(a, b)

a[1] = 22
print(a, b)

print("a id:", id(a))
print("b id:", id(b))


# 输出结果
[1, 2, 3] [1, 2, 3]
[1, 22, 3] [1, 22, 3]
a id: 4567683136
b id: 4567683136
  • 修改 a 变量的值,会同步修改变量 b 的值,因为变量 a、b 指向的对象是可变对象,所以它们保存的对象引用都是一样的

浅拷贝

浅拷贝会创建一个新对象,该新对象存储原始元素的引用

  • (1)不拷贝子对象的内容,只拷贝子对象的引用
  • (2)可以使用Python内置函数copy()

浅拷贝的三种形式

切片-可变序列

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

list1=[1,2,3]
list2=list1[:]

切片是属于浅拷贝,修改数据时,会对原先的造成污染

对于不可变数据类型(元组、字符串):

元组 使用 tuple()和切片操作符:

字符串 使用 str()和切片操作符:

都不是浅拷贝,没有开辟新内存来存储原对象对子对象的引用

列表的切片是浅拷贝(创建新的内存空间),元组的切片是赋值(不会创建新的内存空间)

切片操作符不能用于字典和集合完成浅拷贝

工厂函数-构造器

使用数据类型本身构造器

lst1 = list(lst)

#列表list
list1=[1,2,3]
list2=list(list1)
 
#set
set1=([1,2,3])
set2=set(set1)
 
#字典dict
dict1={1:[1,'w'],2:33}
dict2=dict(dict1)

copy.copy()

list1=[1,2,3]
list2=list1.copy()

import copy  #需要先导入copy模块
 
list1=[1,2,3]
list2=copy.copy(list1)

浅拷贝的原对象的数据改变

浅拷贝在拷贝时,只会copy一层,在内存中开辟一个空间,存放这个copy的列表。更深的层次并没有copy,即第二层用的都是同一个内存。

list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1.append(31)
print(list1)
print(list2)
[(1, 2), 3, [4, 5], 31]
[(1, 2), 3, [4, 5]]
    
    
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list2.append(31)
print(list1)
print(list2)
[(1, 2), 3, [4, 5]]
[(1, 2), 3, [4, 5], 31]
 
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1[0]+=(31,31)
print(list1)
print(list2)
[(1, 2,31,31), 3, [4, 5]]
[(1, 2), 3, [4, 5]]
 
list1=[(1,2),3,[4,5]]
list2=list1.copy()
list1[2]+=[31,31]
print(list1)
print(list2)
[(1, 2), 3, [4, 5,31,31]]
[(1, 2), 3, [4, 5,31,31]]

深拷贝

  • (1)会连子对象的内存全部拷贝一份,对子对象的修改不会影响源对象
  • (2)可以使用Python内置函数deepcopy()
import copy
list_01 = ["11","22"]
list_02 = ["33",list_01]
list_03 = copy.deepcopy(list_02)
print(id(list_01))

print(id(list_02))

print(id(list_03))

print(id(list_02[1]))
print(id(list_03[1]))

list_01.append("44")

print(list_01)
print(list_02)
print(list_03)

['33', ['11', '22', '44']]
['33', ['11', '22']]

通过深拷贝即使嵌套的列表具有更深的层次,也不会产生任何影响,因为深拷贝拷贝出来的对象根本就是一个全新的对象,不再与原来的对象有任何的关联。

总结

  1. 浅拷贝花费时间少,占用内存少,只拷贝顶层数据,拷贝效率高。
  2. 对不可变对象拷贝时,浅拷贝和深拷贝的作用是一致的,不开辟新空间,相当于赋值操作。
  3. 可变对象浅拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化。
  4. 可变对象深拷贝时,会逐层进行拷贝,遇到可变类型,就开辟一块内存复制下来,不论哪一层元素被修改,拷贝的对象都不会发生改变。

不可变对象可以直接赋值,可变对象只有一层时,建议浅拷贝,如果可变对象是多层,建议深拷贝。

标签:python,list,list1,print,拷贝,copy,id
From: https://www.cnblogs.com/tian777/p/17090219.html

相关文章

  • 软件测试|Python基础之面向对象(二)
    面向对象的编程思想面向对象是一种编程思想,用这种思想为指导设计的程序,把数据和对数据的操作封装在一起组成类,通过类来创建对象,通过对象之间的交互来实现程序的功能。面向对......
  • 软件测试|Python基础之面向对象(三)
    Python面向对象之动态静态方法动静态方法在类中定义的函数有多种特性直接在类中定义函数再类中直接定义函数,默认绑定给对象,类调用时有几个参数就要传几个参数,对象调用时该......
  • 软件测试|Python基础之面向对象(四)
    Python面向对象之继承与派生继承python三大特征封装、继承、多态三者中继承最为核心,实际应用多,感受较为直观封装和多态略微抽象继承的概念继承的含义:在现实生活中,继承表......
  • 软件测试|Python基础之模块导入和使用
    Python模块导入和使用模块1、简介本质:模块是指内部具有一定功能(代码)的py文件2、模块的表现形式1、py文件(py文件也可以称之为是模块文件)2、含有多个py文件的文件夹(按照模块功......
  • pycharm设置python头文件模版
    钢铁知识库,一个学习python爬虫、数据分析的知识库。人生苦短,快用python。使用pycharm创建python文件时候,有时候需要自动生成想要的文件头,如何生成呢?只需要以下几步:在f......
  • python之路61 drf从入门到成神 4 反序列化类校验部分源码解析、断言、drf请求、响应格
    反序列化类校验部分源码解析#反序列化校验、什么时候开始执行校验视图类中的ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False#入口:ser.is_valid......
  • python-json的自定义编码器与自定义解码器
    json的数据类型有限,在实际业务中可能会遇到数据无法使用JSON编码的问题。如果我们需要转发的数据有大量或位置不规则的json无法解析数据类型时,事先处理就变成了一件比较麻......
  • 【Azure Cache for Redis】Python Djange-Redis连接Azure Redis服务遇上(104, 'Connec
    问题描述使用Python连接AzureRedis服务,因为在代码中使用的是Djange-redis组件,所以通过如下的配置连接到AzureRedis服务:CACHES={"default":{"BACKEND":"dj......
  • Python 异步: 什么是事件循环 ?(6)
    asyncio程序的核心是事件循环。在本节中,我们将花点时间看一下asyncio事件循环。1.什么是Asyncio事件循环事件循环是用于在单个线程中执行协程的环境。事件循环是异......
  • Python---- 一闭三器
    一闭三器闭包装饰器迭代器生成器闭包保证数据安全闭包结构内层函数对外层函数的局部变量的使用,内层函数被称为闭包函数闭指的是:该函数的内部函数包......