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

news2025/3/4 10:03:42


深浅拷贝是什么:在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)

    应用场景:

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

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


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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解锁GPM 2.0「卡顿帧堆栈」|代码示例与实战分析

每个游戏开发者都有一个共同的愿望,那就是能够在无需复现玩家反馈的卡顿现象时,快速且准确地定位卡顿的根本原因。为了实现这一目标,UWA GPM 2.0推出了全新功能 - 卡顿帧堆栈,旨在为开发团队提供高效、精准的卡顿分析工具。在这篇…

微服务,服务治理nacos,负载均衡LOadBalancer,OpenFeign

1.微服务 简单来说,微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在 自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并 且可通过全自动部署机制独立部署。这…

栈和队列的模拟实现

文章目录 一. 回顾栈和队列二. stack的模拟实现stack.hstack.cpp 三. queue的模拟实现queue.htest.cpp 四. 了解dequeuevector和list都有各自的缺陷deque 总结 一. 回顾栈和队列 回顾一下栈和队列 栈:stack:后进先出 _ 队列:queue&#xf…

unity pico开发 四 物体交互 抓取 交互层级

文章目录 手部设置物体交互物体抓取添加抓取抓取三种类型抓取点偏移抓取事件抓取时不让物体吸附到手部 射线抓取交互层级 手部设置 为手部(LeftHandController)添加XRDirInteractor脚本 并添加一个球形碰撞盒,勾选isTrigger,调整大小为0.1 …

【PromptCoder + Cursor】利用AI智能编辑器快速实现设计稿

【PromptCoder Cursor】利用AI智能编辑器快速实现设计稿 官网:PromptCoder 在现代前端开发中,将设计稿转化为可运行的代码是一项耗时的工作。然而,借助人工智能工具,这一过程可以变得更加高效和简单。本文将介绍如何结合 Promp…

MySQL面试01

MySQL 索引的最左原则 🍰 最左原则本质 ͟͟͞͞( •̀д•́) 想象复合索引是电话号码簿! 索引 (a,b,c) 的排列顺序: 先按a排序 → a相同按b排序 → 最后按c排序 生效场景三连: 1️⃣ WHERE a1 ✅ 2️⃣ WHERE a1 AND b2 ✅ 3️…

webpack一篇

目录 一、构建工具 1.1简介 二、Webpack 2.1概念 2.2使用步骤 2.3配置文件(webpack.config.js) mode entry output loader plugin devtool 2.4开发服务器(webpack-dev-server) grunt/glup的对比 三、Vite 3.1概念 …

健康饮食,健康早餐

营养早餐最好包含4大类食物:谷薯类;碳水;蛋白质;膳食纤维。 1.优质碳水 作用:提供持久的能量,避免血糖大幅波动等 例如:全麦面包、红薯🍠、玉米🌽、土豆🥔、…

【经验分享】Ubuntu20.04 vmware虚拟机存储空间越来越小问题(已解决)

【经验分享】Ubuntu20.04 vmware虚拟机存储空间越来越小问题(已解决) 前言一、问题分析二、解决方案 前言 我们在使用虚拟机过程中,经常会碰到即使删除了一些文件,但是存储空间还是越来越小的问题。今天我们来解决下这个问题。 一…

Jenkins-自动化部署-通知

场景 使用jenkins部署,但有时不能立马部署,需要先通知相关人员,再部署,如果确实不能部署,可以留时间撤销。 方案 1.开始前我们添加,真正开始执行的等待时间;可供选择(Choice Param…

Qt 文件操作+多线程+网络

文章目录 1. 文件操作1.1 API1.2 例子1,简单记事本1.3 例子2,输出文件的属性 2. Qt 多线程2.1 常用API2.2 例子1,自定义定时器 3. 线程安全3.1 互斥锁3.2 条件变量 4. 网络编程4.1 UDP Socket4.2 UDP Server4.3 UDP Client4.4 TCP Socket4.5 …

《基于Hadoop的青岛市旅游景点游客行为分析系统设计与实现》开题报告

目录 一、选题依据 1.选题背景 2.国内外研究现状 (1)国内研究现状 (2)国外研究现状 3.发展趋势 4.应用价值 二、研究内容 1.学术构想与思路 2. 拟解决的关键问题 3. 拟采取的研究方法 4. 技术路线 (1)旅游前准备阶段 …

pycharm debug卡住

pycharm debug时一直出现 collecting data, 然后点击下一行就卡住。 勾选 Gevent compatible解决 https://stackoverflow.com/questions/39371676/debugger-times-out-at-collecting-data

ISP 常见流程

1.sensor输出:一般为raw-OBpedestal。加pedestal避免减OB出现负值,同时保证信号超过ADC最小电压阈值,使信号落在ADC正常工作范围。 2. pedestal correction:移除sensor加的基底,确保后续处理信号起点正确。 3. Linea…

java数据结构_Map和Set(一文理解哈希表)_9.3

目录 5. 哈希表 5.1 概念 5.2 冲突-概念 5.3 冲突-避免 5.4 冲突-避免-哈希函数的设计 5.5 冲突-避免-负载因子调节 5.6 冲突-解决 5.7 冲突-解决-闭散列 5.8 冲突-解决-开散列 / 哈希桶 5.9 冲突严重时的解决办法 5. 哈希表 5.1 概念 顺序结构以及平衡树中&#x…

基于SpringBoot的“数据驱动的资产管理系统站”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“数据驱动的资产管理系统站”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 局部E-R图 系统登录界…

excel 斜向拆分单元格

右键-合并单元格 右键-设置单元格格式-边框 在设置好分割线后,你可以开始输入文字。 需要注意的是,文字并不会自动分成上下两行。 为了达到你期望的效果,你可以通过 同过左对齐、上对齐 空格键或使用【AltEnter】组合键来调整单元格中内容的…

深入理解推理语言模型(RLM)

大语言模型从通用走向推理,万字长文解析推理语言模型,建议收藏后食用。 本文基于苏黎世联邦理工学院的论文《Reasoning Language Models: A Blueprint》进行整理,你将会了解到: 1、RLM的演进与基础:RLM融合LLM的知识广…

2025年具有百度特色的软件测试面试题

百度业务场景 如何测试一个高并发的搜索系统(如百度搜索)?如何测试一个在线地图服务(如百度地图)?如何测试一个大型推荐系统(如百度推荐)的性能?百度技术栈 你对百度的 PaddlePaddle 框架有了解吗?如何测试基于 PaddlePaddle 的服务?如何测试百度云的 API 服务?你对…

Lua | 每日一练 (5)

💢欢迎来到张胤尘的技术站 💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 Lua | 每日一练 (5)题目参考答案浅拷贝深拷贝使用场景…