进来了解一下python的深浅拷贝


深浅拷贝是什么:在Python中,理解深拷贝(deep copy)和浅拷贝(shallow copy)对于处理复杂的数据结构,如列表、字典或自定义对象,是非常重要的。这两种拷贝方式决定了数据在内存中的复制方式,进而影响程序的运行结果


浅拷贝:

1. 浅拷贝的定义:

浅拷贝是一种复制操作,它创建一个新对象,并将原对象的内容复制到新对象中。对于原对象内部的子对象,浅拷贝不会递归地复制它们,而是直接引用这些子对象。因此,浅拷贝后的对象和原对象共享内部的子对象。

2. 浅拷贝的实现方式

(1)使用 copy 模块的 copy() 函数

import copy

original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list)

 (2)使用列表、字典等数据结构的工厂函数

original_list = [1, 2, [3, 4]]
shallow_copied_list = list(original_list)  # 列表的工厂函数

 (3)使用切片操作(适用于列表)

original_list = [1, 2, [3, 4]]
shallow_copied_list = original_list[:]  # 切片操作

(4)使用字典的 copy() 方法

original_dict = {'a': 1, 'b': [2, 3]}
shallow_copied_dict = original_dict.copy()  # 字典的 copy() 方法

 3.浅拷贝的特点

  • 新对象,旧引用:浅拷贝会创建一个新对象,但对象内部的子对象仍然是原对象中子对象的引用。

  • 共享子对象:如果原对象包含可变子对象(如列表、字典等),修改这些子对象会影响浅拷贝后的对象。

  • 性能较高:由于浅拷贝不会递归复制子对象,因此它的性能比深拷贝更高。


    4. 浅拷贝的示例

示例 1:修改浅拷贝后的对象 

import copy

original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list)

# 修改浅拷贝后的对象
shallow_copied_list[0] = 100
shallow_copied_list[2][0] = 300

print("Original List:", original_list)
print("Shallow Copied List:", shallow_copied_list)

输出

Original List: [1, 2, [300, 4]]
Shallow Copied List: [100, 2, [300, 4]]

解释:

  • 修改 shallow_copied_list[0] 不会影响 original_list,因为这是对新对象本身的修改。

  • 修改 shallow_copied_list[2][0] 会影响 original_list,因为内部的子列表是共享的。

示例 2:使用切片操作实现浅拷贝 

original_list = [1, 2, [3, 4]]
shallow_copied_list = original_list[:]

# 修改浅拷贝后的对象
shallow_copied_list[0] = 100
shallow_copied_list[2][0] = 300

print("Original List:", original_list)
print("Shallow Copied List:", shallow_copied_list)

输出

Original List: [1, 2, [300, 4]]
Shallow Copied List: [100, 2, [300, 4]]

示例 3:字典的浅拷贝

original_dict = {'a': 1, 'b': [2, 3]}
shallow_copied_dict = original_dict.copy()

# 修改浅拷贝后的字典
shallow_copied_dict['a'] = 100
shallow_copied_dict['b'][0] = 200

print("Original Dict:", original_dict)
print("Shallow Copied Dict:", shallow_copied_dict)

输出

Original Dict: {'a': 1, 'b': [200, 3]}
Shallow Copied Dict: {'a': 100, 'b': [200, 3]}

解释:

  • 修改 shallow_copied_dict['a'] 不会影响 original_dict,因为这是对新对象本身的修改。

  • 修改 shallow_copied_dict['b'][0] 会影响 original_dict,因为内部的列表是共享的。


 5. 浅拷贝的适用场景

浅拷贝适用于以下场景:

  • 对象内部没有嵌套的可变对象:如果对象内部只包含不可变对象(如整数、字符串、元组等),浅拷贝是安全的。

  • 性能要求较高:浅拷贝的性能比深拷贝更高,因为它不会递归复制子对象。

  • 共享子对象是期望的行为:如果你希望拷贝后的对象和原对象共享某些子对象,浅拷贝是一个合适的选择。


    6. 浅拷贝的注意事项

 

  • 共享子对象的风险:如果原对象包含可变子对象,修改这些子对象会影响浅拷贝后的对象。如果不希望共享子对象,应该使用深拷贝。

  • 不可变对象的特殊性:对于不可变对象(如整数、字符串、元组等),浅拷贝和深拷贝的行为是相同的,因为不可变对象不能被修改。


    深拷贝:


    深拷贝(Deep Copy)是Python中一种递归复制对象的方式,它会创建一个新对象,并递归地复制原对象内部的所有子对象。这意味着深拷贝后的对象与原对象完全独立,修改其中一个不会影响另一个。深拷贝适用于需要完全独立副本的场景,尤其是当对象内部包含嵌套的可变对象时。


 1. 深拷贝的定义

深拷贝是一种递归复制操作,它创建一个新对象,并递归地复制原对象内部的所有子对象。深拷贝后的对象与原对象完全独立,即使原对象包含嵌套的可变对象(如列表、字典等),修改其中一个对象也不会影响另一个。


 2. 深拷贝的实现方式

在Python中,可以通过 copy 模块的 deepcopy() 函数实现深拷贝。

使用 copy.deepcopy() 函数

3. 深拷贝的特点

  • 完全独立:深拷贝后的对象与原对象完全独立,修改其中一个不会影响另一个。

  • 递归复制:深拷贝会递归地复制对象内部的所有子对象,包括嵌套的可变对象。

  • 性能较低:由于深拷贝需要递归复制所有子对象,因此它的性能比浅拷贝低,尤其是在处理大型或复杂的嵌套结构时。


    4. 深拷贝的示例

 

通过以下示例,可以更好地理解深拷贝的行为。

示例 1:修改深拷贝后的对象

输出: 

Original List: [1, 2, [3, 4]]
Deep Copied List: [100, 2, [300, 4]]

解释:

  • 修改 deep_copied_list[0] 不会影响 original_list,因为这是对新对象本身的修改。

  • 修改 deep_copied_list[2][0] 也不会影响 original_list,因为深拷贝递归复制了内部的子列表,两个列表是完全独立的。

  • 示例 2:嵌套字典的深拷贝

输出: 

Original Dict: {'name': 'Alice', 'details': {'age': 25, 'hobbies': ['reading', 'traveling']}}
Deep Copied Dict: {'name': 'Alice', 'details': {'age': 30, 'hobbies': ['reading', 'traveling', 'cooking']}}

解释:

  • 修改 deep_copied_dict 中的嵌套字典和列表不会影响 original_dict,因为深拷贝递归复制了所有子对象。

示例 3:自定义对象的深拷贝

输出 

解释:

  • 修改 person2 的 name 和 friends 不会影响 person1,因为深拷贝递归复制了所有属性。


    5. 深拷贝的适用场景

    深拷贝适用于以下场景:

  • 需要完全独立的副本:当对象内部包含嵌套的可变对象时,深拷贝可以确保副本与原对象完全独立。

  • 复杂的数据结构:如嵌套的列表、字典、自定义对象等。

  • 避免副作用:在函数中传递复杂对象时,深拷贝可以避免意外修改原对象。


    6. 深拷贝的注意事项

  • 性能开销:深拷贝需要递归复制所有子对象,因此在处理大型或复杂的嵌套结构时,性能开销较大。

  • 循环引用问题:如果对象之间存在循环引用(如对象A引用对象B,对象B又引用对象A),深拷贝可能会导致栈溢出或无限递归。Python的 copy.deepcopy() 函数已经处理了循环引用问题,但在自定义深拷贝逻辑时需要注意。


    7. 深拷贝的实现原理

    Python的 copy.deepcopy() 函数通过递归遍历对象的所有属性来实现深拷贝。它会维护一个备忘录(memo)来记录已经复制的对象,从而避免循环引用导致的无限递归。


    深浅拷贝的实际应用:

深浅拷贝在实际编程中有广泛的应用,尤其是在处理复杂数据结构或需要确保数据独立性时。以下是一些常见的应用场景和示例,帮助你更好地理解它们的实际用途。 


1. 数据处理与修改

在处理数据时,尤其是嵌套的数据结构(如列表嵌套列表、字典嵌套字典等),你可能需要在不影响原始数据的情况下对数据进行修改或分析。这时,深拷贝非常有用。 

import copy

# 原始数据
original_data = {
    'name': 'Alice',
    'scores': [90, 85, 88],
    'details': {'age': 25, 'city': 'New York'}
}

# 深拷贝数据
copied_data = copy.deepcopy(original_data)

# 修改拷贝后的数据
copied_data['scores'][0] = 95
copied_data['details']['city'] = 'San Francisco'

# 原始数据不受影响
print("Original Data:", original_data)
print("Copied Data:", copied_data)

应用场景:

  • 数据备份与恢复。

  • 数据预处理(如修改数据后用于机器学习模型训练,而不影响原始数据)。


    2. 配置管理

在程序中,配置通常以字典或嵌套字典的形式存储。如果你需要基于某个默认配置生成多个独立的配置,深拷贝可以确保每个配置之间互不干扰。 

import copy

# 默认配置
default_config = {
    'debug': False,
    'database': {
        'host': 'localhost',
        'port': 3306
    }
}

# 创建多个独立配置
config_1 = copy.deepcopy(default_config)
config_2 = copy.deepcopy(default_config)

# 修改配置
config_1['database']['host'] = '192.168.1.1'
config_2['debug'] = True

print("Config 1:", config_1)
print("Config 2:", config_2)

应用场景:

  • 多环境配置(开发、测试、生产)。

  • 动态生成多个独立的配置。


    3. 对象复制与状态管理

在面向对象编程中,对象可能包含嵌套的对象或复杂的状态。如果你需要复制一个对象并确保新对象的状态独立于原对象,深拷贝是必要的。 

import copy

class Player:
    def __init__(self, name, level):
        self.name = name
        self.level = level
        self.inventory = []

    def add_item(self, item):
        self.inventory.append(item)

# 创建玩家对象
player1 = Player("Alice", 10)
player1.add_item("Sword")
player1.add_item("Shield")

# 深拷贝玩家对象
player2 = copy.deepcopy(player1)

# 修改拷贝后的对象
player2.name = "Bob"
player2.add_item("Bow")

# 查看两个对象的状态
print(f"Player 1: {player1.name}, {player1.inventory}")
print(f"Player 2: {player2.name}, {player2.inventory}")

应用场景:

  • 游戏开发中复制角色或物品。

  • 状态快照与恢复(如撤销操作)。


    4. 避免副作用

    def process_data(data):
        # 浅拷贝数据以避免修改原始数据
        data_copy = data.copy()
        data_copy.append("Processed")
        return data_copy
    
    original_data = [1, 2, 3]
    result = process_data(original_data)
    
    print("Original Data:", original_data)
    print("Result:", result)

    应用场景:

  • 函数式编程中避免副作用。

  • 数据处理管道中确保数据独立性。


  • 深拷贝:适用于需要完全独立副本的场景,如数据处理、配置管理、对象复制等。

  • 浅拷贝:适用于性能敏感的场景,或者当对象内部没有嵌套结构时。

建议 选择使用深拷贝还是浅拷贝取决于具体的需求和数据结构。如果你不确定,深拷贝通常是更安全的选择,尽管它可能会带来一些性能开销。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980919.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

磁盘空间不足|如何安全清理以释放磁盘空间(开源+节流)

背景: 最近往数据库里存的东西有点多,磁盘不够用 查看磁盘使用情况 df -h /dev/sda5(根目录 /) 已使用 92% 咱们来开源节流 目录 背景: 一、开源 二、节流 1.查找 大于 500MB 的文件: 1. Snap 缓存…

vue3学习-2(深入组件)

vue3学习-2(深入组件) 1.开始2.基础3.深入组件注册全局注册局部注册组件名格式 PropsProps 声明响应式 Props 解构 3.5将解构的 props 传递到函数中单向数据流更改对象 / 数组类型的 propsProp 校验 事件触发与监听事件事件参数声明触发的事件事件校验 组…

Java 入门 (超级详细)

一、什么是Java Java是一种高级编程语言,由Sun Microsystems公司于1995年推出。Java具有跨平台性、面向对象、健壮性、安全性、可移植性等特点,被广泛应用于企业级应用开发、移动应用开发、大数据处理、云计算等领域。Java程序可以在不同的操作系统上运…

23种设计模式之工厂方法模式(Factory Method Pattern)【设计模式】

文章目录 一、工厂方法模式简介二、关键点三、代码示例3.1 定义抽象产品3.2 实现具体产品3.3 创建抽象工厂3.4 实现具体工厂3.5 客户端代码 四、解释五、优缺点5.1 优点5.2 缺点 六、适用场景 一、工厂方法模式简介 工厂方法模式(Factory Method Pattern&#xff0…

io学习----->标准io

思维导图: 一.io的作用 io是实现对文件的操作,把运行结果存到文件中,读取文件的数据,方便后期查询。 二.io的概念 io是指系统 和外部设备或用户之间的数据交互 I:input 表示数据从外部设备输入到内存中; O:output…

从 R1 到 Sonnet 3.7,Reasoning Model 首轮竞赛中有哪些关键信号?

DeepSeek R1 催化了 reasoning model 的竞争:在过去的一个月里,头部 AI labs 已经发布了三个 SOTA reasoning models:OpenAI 的 o3-mini 和deep research, xAI 的 Grok 3 和 Anthropic 的 Claude 3.7 Sonnet。随着头部 Al labs 先…

FPGA开发,使用Deepseek V3还是R1(7):以“FPGA的整体设计框架”为例

以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&#x…

正大杯攻略|非量表题数据分析基本步骤

在各类研究和调查场景中,非量表类问卷作为数据收集的重要工具,其分析方法涵盖多个关键环节,对于精准解读数据、提炼有价值的结论起着决定性作用。下面详细介绍非量表类问卷的分析方法。 一、样本背景分析 样本背景分析借助描述性统计方法&am…

SuperMap iClient3D for WebGL三维场景与二维地图联动

作者:Lzzzz 在城市规划,应急救援,旅游规划等项目场景中,普遍存在通过二维地图定位区域或路线,三维场景展示布局细节的情况,那么,如何使三维场景与二维地图联动起来呢,一起来看看如何…

3dsmax烘焙光照贴图然后在unity中使用

效果预览 看不清[完蛋!] 实现步骤 使用 软件 软体名称地址photoshophttps://www.adobe.com/products/photoshop.htmlunity3Dhttps://unity.com/3dsmaxhttps://www.autodesk.com.cn/products/3ds-max/free-trialpacker-iohttps://www.uv-packer.com/HDR 贴图地址…

ThinkPHP使用phpword读取模板word文件并添加表格

1.安装phpword包composer require phpoffice/phpword 2.模板文件结构 如上图框住的是要替换的文本和要复制表格样式 实现代码 <?phpnamespace app\api\logic;use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\…

Solon AI —— 流程编排

说明 Solon 的流程编排&#xff0c;使用了 solon-flow 做流程编排&#xff0c;因此需要先对 solon-flow 有所了解&#xff0c;下面是 Solon flow的一些简单介绍&#xff0c;更具体的介绍可以参考官网 https://solon.noear.org/article/learn-solon-flow 。 solon-flow Solon…

性能调优-cpu的性能指标【经典篇】

一 cpu查看core数命令 1.1 查看物理core数 1.查看物理CPU的个数&#xff1a;cat /proc/cpuinfo 这个虚拟机的物理cpu2个&#xff0c;每个物理cpu的逻辑CPU个数为1个&#xff0c;所以逻辑CPU的个数就是2个。 1.2 查看逻辑cpu个数 cat /proc/cpuinfo| grep "processo…

Unity中动态切换光照贴图LightProbe的方法

关键代码&#xff1a;LightmapSettings.lightmaps lightmapDatas; LightmapData中操作三张图&#xff1a;lightmapColor,lightmapDir,以及一张ShadowMap 这里只操作前两张&#xff1a; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;public cl…

计算机毕业设计Python+DeepSeek-R1大模型微博舆情分析系统 微博舆情预测 微博爬虫 微博大数 据(源码+LW文档+PPT+详细讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

[Computer Vision]实验八:图像分割

目录 一、实验内容 二、实验过程 2.1 交互式分割实验 2.1.1 交互式分割 实验代码 2.1.2 实验结果 2.2 聚类算法实现图像分割 2.2.1 聚类算法实现分割 实验代码 2.2.2 实验结果 三、实验总结 一、实验内容 了解图割操作&#xff0c;实现用户交互式分割&#xff0c;通过…

Django与数据库

我叫补三补四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲alpha策略制定后的测试问题 mysql配置 Django模型体现了面向对象的编程技术&#xff0c;是一种面向对象的编程语言和不兼容类型能相互转化的编程技术&#xff0c;这种技术也叫ORM&#…

命名管道——进程间通信

个人主页&#xff1a;敲上瘾-CSDN博客 匿名管道&#xff1a;进程池的制作&#xff08;linux进程间通信&#xff0c;匿名管道... ...&#xff09;-CSDN博客 一、命名管道的使用 1.创建命名管道 1.1.在命令行中&#xff1a; 创建&#xff1a; mkfifo 管道名 删除&#xff1a…

摄像头应用编程(三):多平面视频采集

文章目录 1、前言2、环境介绍3、步骤4、应用程序编写5、测试5.1、编译应用程序5.2、运行应用程序 6、总结 1、前言 在查看摄像头类型时&#xff0c;大致可以分为两类&#xff1a;Video Capture 和 Video Capture Multiplanar。 本次应用程序主要针对类型为Video Capture Multi…

QT实现计算器

1&#xff1a;在注册登录的练习里面&#xff0c; 追加一个QListWidget 项目列表 要求&#xff1a;点击注册之后&#xff0c;将账号显示到 listWidget上面去 以及&#xff0c;在listWidget中双击某个账号的时候&#xff0c;将该账号删除 Widget.h #ifndef WIDGET_H #define…