Python - 对象赋值、浅拷贝、深拷贝的区别(上)

简介: Python - 对象赋值、浅拷贝、深拷贝的区别(上)

前言


  • Python 中不存在值传递,一切传递的都是对象的引用,也可以认为是传址
  • 这里会讲三个概念:对象赋值、浅拷贝、深拷贝

 

名词解释


  • 变量:存储对象的引用
  • 对象:会被分配一块内存,存储实际的数据,比如字符串、数字、列表
  • 引用:变量指向对象,可以理解为指针


image.png

实际的一种应用场景


  • 有一个变量 a,存储了一个值
  • 此时想用另一个变量 b 暂时存储变量 a 的值,以便后续使用
  • 然后继续修改变量 a 的值,但修改的时候并不想同步更改变量 b 的值

a=1

b=a

a=2

 

对象赋值


 

不可变对象的赋值


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 存储的对象引用已经改变了
  • 至于具体的原理,可以看看不可变对象、可变对象的详解 https://www.cnblogs.com/poloyy/p/15073168.html

 

可变对象的赋值


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 指向的对象是可变对象,所以它们保存的对象引用都是一样的

 

拷贝的诞生

  • 那如果要让可变对象也能满足上述实际应用场景,要怎么做呢?
  • 当然就是拷贝
  • 而拷贝又分为浅拷贝、深拷贝,接下来会具体聊一聊两种拷贝的区别

 

第一个重点总结


  • 对于不可变对象来说,赋值操作其实就可以满足上面说的实际应用场景
  • 所以!后面要讲的浅拷贝、深拷贝对于不可变对象来说,和赋值操作是一样的效果!
  • 记住!浅拷贝、深拷贝只针对可变对象,即列表、集合、字典!

 

copy 模块


Python 提供了 copy 模块,包含了浅拷贝、深拷贝函数

from copy import copy, deepcopy
# 浅拷贝
copy(x)
# 深拷贝
deepcopy(x)


浅拷贝


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

 

浅拷贝后的值是相同的

  • 将列表赋值给变量 old_list
  • 通过 copy() 方法对 old_list 变量指向的对象进行浅拷贝,并赋值给新变量 new_list
  • 因为是对象进行拷贝,所以 new_list 和 old_list 存储的值是相同的


import copy
old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
new_list = copy.copy(old_list)
print("Old list:", old_list)
print("New list:", new_list)
# 输出结果
Old list: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
New list: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


浅拷贝后的会产生一个新的对象

  • 虽然 old_list 和 new_list 存储的值是相同的,但浅拷贝的操作是产生了一个新的对象
  • 所以 old_list 和 new_list 指向的对象并不是同一个
import copy
old_list = [[1, 2], [3, 4]]
new_list = copy.copy(old_list)
old_list.append([5, 6])
print("Old list:", old_list, "id is :", id(old_list))
print("New list:", new_list, "id is :", id(new_list))
# 输出结果
Old list: [[1, 2], [3, 4], [5, 6]] id is : 4366240704
New list: [[1, 2], [3, 4]] id is : 4366246720


可以看到内存地址是不同的,所以给 old_list 新增一个元素并不会同步让 new_list 也新增

 

原理图

image.png

  • 浅拷贝生成了一个新对象,然后赋值给 new_list
  • new_list、old_list 指向的列表对象不是同一个,但值相同
  • 重点:对于列表对象中的元素,浅拷贝产生的新对象只存储原始元素的引用(内存地址),所以两个列表对象的元素的引用都指向同一个内存地址
相关文章
|
6月前
|
索引 Python
Python 列表切片赋值教程:掌握 “移花接木” 式列表修改技巧
本文通过生动的“嫁接”比喻,讲解Python列表切片赋值操作。切片可修改原列表内容,实现头部、尾部或中间元素替换,支持不等长赋值,灵活实现列表结构更新。
309 1
|
6月前
|
存储 Java 索引
(Python基础)新时代语言!一起学习Python吧!(二):字符编码由来;Python字符串、字符串格式化;list集合和tuple元组区别
字符编码 我们要清楚,计算机最开始的表达都是由二进制而来 我们要想通过二进制来表示我们熟知的字符看看以下的变化 例如: 1 的二进制编码为 0000 0001 我们通过A这个字符,让其在计算机内部存储(现如今,A 字符在地址通常表示为65) 现在拿A举例: 在计算机内部 A字符,它本身表示为 65这个数,在计算机底层会转为二进制码 也意味着A字符在底层表示为 1000001 通过这样的字符表示进行转换,逐步发展为拥有127个字符的编码存储到计算机中,这个编码表也被称为ASCII编码。 但随时代变迁,ASCII编码逐渐暴露短板,全球有上百种语言,光是ASCII编码并不能够满足需求
298 4
|
存储 开发者 Python
Python 中的数据结构与其他编程语言数据结构的区别
不同编程语言都有其设计理念和应用场景,开发者需要根据具体需求和语言特点来选择合适的数据结构
648 151
|
Python
[oeasy]python086方法_method_函数_function_区别
本文详细解析了Python中方法(method)与函数(function)的区别。通过回顾列表操作如`append`,以及随机模块的使用,介绍了方法作为类的成员需要通过实例调用的特点。对比内建函数如`print`和`input`,它们无需对象即可直接调用。总结指出方法需基于对象调用且包含`self`参数,而函数独立存在无需`self`。最后提供了学习资源链接,方便进一步探索。
310 17
|
Python
[oeasy]python055_python编程_容易出现的问题_函数名的重新赋值_print_int
本文介绍了Python编程中容易出现的问题,特别是函数名、类名和模块名的重新赋值。通过具体示例展示了将内建函数(如`print`、`int`、`max`)或模块名(如`os`)重新赋值为其他类型后,会导致原有功能失效。例如,将`print`赋值为整数后,无法再用其输出内容;将`int`赋值为整数后,无法再进行类型转换。重新赋值后,这些名称失去了原有的功能,可能导致程序错误。总结指出,已有的函数名、类名和模块名不适合覆盖赋新值,否则会失去原有功能。如果需要使用类似的变量名,建议采用其他命名方式以避免冲突。
326 14
|
存储 Python
[oeasy]python056_python中下划线是什么意思_underscore_理解_声明与赋值_改名字
在Python中,下划线有多种用途。单下划线(_)常用于避免命名冲突,如将`max`改为`max_`以保留内置函数功能。双下划线(__var__)通常用于特殊方法和属性,如`__name__`、`__doc__`等。此外,单下划线(_)在交互式解释器中表示上一次表达式的值,但不建议作为普通变量名使用。总结:下划线用于避免命名冲突及特殊标识。
373 1
|
Python 容器
[oeasy]python048_用变量赋值_连等赋值_解包赋值_unpack_assignment _
本文介绍了Python中变量赋值的不同方式,包括使用字面量和另一个变量进行赋值。通过`id()`函数展示了变量在内存中的唯一地址,并探讨了变量、模块、函数及类类型的地址特性。文章还讲解了连等赋值和解包赋值的概念,以及如何查看已声明的变量。最后总结了所有对象(如变量、模块、函数、类)都有其类型且在内存中有唯一的引用地址,构成了Python系统的基石。
202 5
|
存储 Python 容器
[oeasy]python045_[词根溯源]赋值_assignment_usage_使用
本文回顾了上一次讲解的内容,重点讨论了变量的概念及其在各种系统和游戏中的应用。文章详细解释了变量的声明与赋值操作,强调了赋值即为将具体值存储到变量名下的过程。同时,通过例子说明了字面量(如数字0)不能被赋值给其他值的原因。此外,还探讨了“赋值”一词的来源及其英文表达“assignment”的含义,并简要介绍了与之相关的英语词汇,如sign、assign、signal等。最后,总结了本次课程的核心内容,即赋值操作的定义和实现方式。
239 3
|
Python
Python赋值运算符
Python赋值运算符。
164 2
|
机器学习/深度学习 缓存 Linux
python环境学习:pip介绍,pip 和 conda的区别和联系。哪个更好使用?pip创建虚拟环境并解释venv模块,pip的常用命令,conda的常用命令。
本文介绍了Python的包管理工具pip和环境管理器conda的区别与联系。pip主要用于安装和管理Python包,而conda不仅管理Python包,还能管理其他语言的包,并提供强大的环境管理功能。文章还讨论了pip创建虚拟环境的方法,以及pip和conda的常用命令。作者推荐使用conda安装科学计算和数据分析包,而pip则用于安装无法通过conda获取的包。
2428 0

推荐镜像

更多