Python 的赋值,浅拷贝和深拷贝详解

Python 的赋值、浅拷贝和深拷贝详解

赋值、浅拷贝和深拷贝是 Python 中经常涉及的概念,也是容易混淆的概念。本文将详细讲解这三个概念的定义、区别和示例说明。

赋值

赋值是将一个对象的引用复制给另一个变量,让它指向同一个对象。例如:

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

前面的语句将 [1, 2, 3] 这个列表对象赋值给了 a 变量,而 b 变量则将 a 变量的引用复制一份成为自己的引用。这时候 ab 两个变量都指向同一个列表对象。修改 ab 变量所指向的列表,另一个变量所指向的列表也会发生相应的变化。

a[0] = 0
print(a)  # [0, 2, 3]
print(b)  # [0, 2, 3]

浅拷贝

浅拷贝是创建一个新的对象,但是新对象作为容器只包括原对象的引用。例如:

import copy

a = [1, 2, [3, 4]]
b = copy.copy(a)

与赋值不同的是,浅拷贝是通过对原对象的某些层次进行复制,创建一个新的对象,并将原对象中的引用复制到新对象中。在这个过程中,新对象与原对象共享内部列表这样的可变对象。当修改内部的可变对象时,两个变量所指向的列表不同,但是它们所包含的对象相同。

a[0] = 0
a[2][0] = 0
print(a)  # [0, 2, [0, 4]]
print(b)  # [1, 2, [0, 4]]

深拷贝

深拷贝是创建一个新的对象,包括原对象及其所有子对象的拷贝。例如:

import copy

a = [1, 2, [3, 4]]
b = copy.deepcopy(a)

深拷贝与浅拷贝的区别在于对于原对象的子对象,深拷贝将递归地进行子对象的复制,创建一整个新的对象,而浅拷贝仅仅是对子对象内层的引用进行复制,会影响子对象中共享的可变对象。

a[0] = 0
a[2][0] = 0
print(a)  # [0, 2, [0, 4]]
print(b)  # [1, 2, [3, 4]]

由于深拷贝是递归进行的,当对象的层次很深或者包含循环引用时,深拷贝的性能会变得很低。这时候可以考虑使用其他的方法来减少拷贝的次数。

示例说明

示例一

import copy

a = [1, 2, [3, 4]]
b = a  # 赋值
c = copy.copy(a)  # 浅拷贝
d = copy.deepcopy(a)  # 深拷贝

a[0] = 0
a[2][0] = 0

print(a)  # [0, 2, [0, 4]]
print(b)  # [0, 2, [0, 4]]
print(c)  # [1, 2, [0, 4]]
print(d)  # [1, 2, [3, 4]]

在这个示例中,我们创建了一个嵌套列表的对象,并通过赋值、浅拷贝和深拷贝分别创建了三个新的变量。我们修改了 a 变量所指向的列表对象的元素值,即 [1, 2, [3, 4]] -> [0, 2, [0, 4]]。并且,我们也修改了 a 变量所指向的列表对象中的嵌套列表对象的元素值,即 [3, 4] -> [0, 4]。我们可以看到,赋值和浅拷贝得到的变量所指向的列表对象同样发生了变化,而深拷贝得到的变量所指向的列表对象不受影响。

示例二

import copy

a = [1, 2]
b = [3, 4]
c = [a, b]
d = [a, b]
e = copy.copy(c)
f = copy.deepcopy(c)

print(c is d)  # False
print(c == d)  # True

a[0] = 0
print(c)  # [[0, 2], [3, 4]]
print(d)  # [[1, 2], [3, 4]]
print(e)  # [[0, 2], [3, 4]]
print(f)  # [[1, 2], [3, 4]]

在这个示例中,我们创建了两个嵌套列表的对象,并将它们组成一个新的嵌套列表对象。我们使用了赋值、浅拷贝和深拷贝分别创建了三个新的嵌套列表对象。我们设置了 cd 变量分别指向同样的嵌套列表对象。我们修改了 a 变量所指向的列表对象的元素值,即 [1, 2] -> [0, 2]。我们用 is 判断了 cd 变量是否指向同样的列表对象,结果为 False。我们可以看到,浅拷贝得到的变量所指向的嵌套列表对象虽然不受 内部可变对象 的影响,但是共享同样的父对象;而深拷贝得到的变量所指向的嵌套列表对象完全独立,不受任何对象的影响。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 的赋值,浅拷贝和深拷贝详解 - Python技术站

(0)
上一篇 2023年6月5日
下一篇 2023年6月5日

相关文章

  • Python+OpenCV图像处理——实现直线检测

    Python+OpenCV图像处理——实现直线检测 本文将介绍如何使用Python和OpenCV包实现直线检测。直线检测在图像处理中起着非常重要的作用。我们可以使用Hough变换来检测直线,Hough变换是一种将参数空间(极坐标)中的曲线转换为图像空间中的点的方法。 步骤一:读取待处理的图像 在使用Python中的OpenCV进行图像处理之前,我们需要先读取…

    python 2023年5月18日
    00
  • python中如何正确使用正则表达式的详细模式(Verbose mode expression)

    Python中如何正确使用正则表达式的详细模式(Verbose mode expression) 正则表达式是一种强大的文本处理工具,可以用于各种文本处理,如数据清洗、文本分析、信息提取等。在Python中,我们使用re模块提供的函数来操作正则表达式。本攻略将详细讲解Python中如何正确使用正则表达式的详细模式(Verbose mode expressio…

    python 2023年5月14日
    00
  • 浅谈Python处理json字符串为什么不建议使用eval()

    下面是详细讲解: 为什么不建议使用eval()处理json字符串 在处理json字符串时,可能会想到使用Python内置的eval()函数快速地将json字符串转换为Python对象。但是,使用eval()函数存在着一些潜在的问题,下面我们逐一进行说明。 1. 安全性问题 首先,使用eval()函数需要非常小心,因为它不仅仅能够将json字符串转换为Pyth…

    python 2023年6月3日
    00
  • Python列表的索引与切片

    以下是“Python列表的索引与切片”的完整攻略。 1. 什么是列表索引与切片 列表索引是指通过下标获取列表中的元素,而列表切片是指通过下标范围获取列表中的一部分元素。在Python中,列表索引和切片是非常常用的操作,可以帮助我们快速地访问和操作列表中的元素。 2. 列表索引 列表索引是通过下标获取列表中的元素。在Python中,列表的下标从0开始,即第一个…

    python 2023年5月13日
    00
  • Python numpy实现二维数组和一维数组拼接的方法

    下面是详细讲解 “Python numpy实现二维数组和一维数组拼接的方法” 的攻略。 一、numpy.concatenate()方法 使用numpy的方法concatenate()可以实现二维数组和一维数组拼接。例如,我们有一个2×3的二维数组和一个大小为3的一维数组: import numpy as np a = np.array([[1, 2, 3],…

    python 2023年6月6日
    00
  • python粘包问题及socket套接字编程详解

    下面我们来详细讲解一下“Python粘包问题及Socket套接字编程详解”的攻略。 什么是粘包问题? 在Socket套接字编程中,发送端发送的多个小数据包可能会被接收端合并成一个大数据包,这就是粘包问题。造成这种情况的原因是TCP协议是面向流的,没有数据边界的概念,因此发送的数据无法保证一定是发送端所希望的大小。 如何解决粘包问题? 解决粘包问题的方法有很多…

    python 2023年6月6日
    00
  • python爬虫分布式获取数据的实例方法

    我来为您详细讲解 “Python爬虫分布式获取数据的实例方法” 的完整攻略。 什么是Python爬虫分布式? Python爬虫分布式是指将一个爬虫程序在多台计算机上执行,可以大大提高爬虫的性能和效率。通常情况下,Python爬虫分布式使用的工具是Scrapy-Redis,它是Scrapy和Redis结合使用的分布式爬虫框架。 Python爬虫分布式获取数据的…

    python 2023年5月14日
    00
  • Python爬虫:将headers请求头字符串转为字典的方法

    前言 在使用Python进行网络爬取时,对于请求网站的Headers信息处理非常重要。有些情况下我们需要手动填写Headers请求头,这时候我们可以将Headers字符串转换成字典,方便进行添加、修改等操作。 将Headers请求头字符串转为字典 在Python中,请求头可以用字符串表示,也可以用字典表示。因此,转换字符串为字典的方法就比较简单了,只需要调用…

    python 2023年5月13日
    00
合作推广
合作推广
分享本页
返回顶部