图解Python深拷贝和浅拷贝

参见连接:http://www.cnblogs.com/wilber2013/p/4645353.html

总结:

  • Python中对象的赋值都是进行对象引用(内存地址)传递
  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
  • 对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说
  • 如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子

<think>我们正在讨论深拷贝浅拷贝的概念及其区别。根据引用内容,我们可以总结如下: 1. 深拷贝浅拷贝主要针对引用数据类型(如对象、数组等),因为基本数据类型在赋值时是直接复制值,修改新变量不会影响原变量。 2. 浅拷贝(Shallow Copy): - 只复制对象的第一层属性。 - 如果属性是基本类型,则复制其值;如果是引用类型,则复制其内存地址(即指针),因此新旧对象共享同一块内存。 - 修改新对象的引用类型属性会影响到原对象,因为两者指向同一个内存地址。 - 可能引发内存重复释放等问题(例如在C++等语言中)。 3. 深拷贝(Deep Copy): - 递归复制对象的所有层级,直到所有属性都是基本类型为止。 - 为新对象创建新的内存空间,新旧对象完全独立,互不影响。 - 修改新对象的任何属性都不会影响原对象。 - 实现上比浅拷贝复杂,但更安全。 区别总结: | 特性 | 浅拷贝 | 深拷贝 | |--------------|------------------------------------------|------------------------------------------| | 复制层级 | 仅第一层 | 所有层级(递归复制) | | 引用类型复制 | 复制地址(共享内存) | 创建新内存(独立) | | 修改影响 | 新对象修改引用类型属性会影响原对象 | 新对象修改属性不会影响原对象 | | 实现复杂 | 简单 | 复杂 | | 内存占用 | 较少(共享部分内存) | 较多(完全独立内存) | | 安全性 | 较低(可能内存共享问题) | 较高 | 实现深拷贝的方法(以JavaScript为例): 1. 使用JSON序列化反序列化(但有局限性,如不能复制函数、循环引用会报错等): ```javascript let newObj = JSON.parse(JSON.stringify(oldObj)); ``` 2. 递归实现: ```javascript function deepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; } let clone = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key]); } } return clone; } ``` 3. 使用第三方库(如lodash的`_.cloneDeep`): ```javascript let newObj = _.cloneDeep(oldObj); ``` 注意事项: - 浅拷贝方法:`Object.assign()`、扩展运算符`...`、数组的`slice()``concat()`等。 - 深拷贝需要考虑循环引用、函数、特殊对象(如Date、RegExp)等复杂情况。 在编程中,选择深拷贝还是浅拷贝取决于需求。如果对象结构简单且不需要独立修改,浅拷贝即可;如果对象嵌套复杂且需要完全独立,则使用深拷贝。 相关问题: 1. 在JavaScript中,如何实现一个支持循环引用的深拷贝函数? 2. 深拷贝浅拷贝在性能上有什么差异?如何选择? 3. 在Java语言中,深拷贝浅拷贝如何实现? 4. JSON序列化实现深拷贝有哪些局限性? 5. 如何避免深拷贝过程中出现栈溢出问题?</think>### 深拷贝浅拷贝的概念解析 #### 一、基本定义 1. **浅拷贝 (Shallow Copy)** - 仅复制对象的**第一层属性值**(包括基本类型值引用地址) - 当属性为引用类型时,复制的是**内存地址指针**而非实际数据 - 新旧对象**共享**引用类型属性的内存空间[^1][^3] ```javascript // JavaScript浅拷贝示例 const original = { a: 1, b: { c: 2 } }; const shallowCopy = { ...original }; // 扩展运算符实现浅拷贝 shallowCopy.b.c = 99; // 修改会影响原对象 console.log(original.b.c); // 输出99 ``` 2. **深拷贝 (Deep Copy)** - 递归复制对象的**所有层级属性** - 为所有引用类型属性**创建新的内存空间** - 新旧对象**完全独立**,互不影响[^1][^3][^4] ```javascript // JavaScript深拷贝示例(通过JSON方式) const original = { a: 1, b: { c: 2 } }; const deepCopy = JSON.parse(JSON.stringify(original)); deepCopy.b.c = 99; // 修改不影响原对象 console.log(original.b.c); // 输出2 ``` #### 二、核心区别对比 | **特性** | 浅拷贝 | 深拷贝 | |------------------|-------------------------------|-------------------------------| | **复制深度** | 仅第一层属性 | 递归所有层级 | | **引用类型处理** | 复制指针(共享内存) | 创建新内存(独立数据) | | **内存占用** | 较低 | 较高 | | **修改影响** | 影响原对象[^2][^4] | 不影响原对象[^1][^3] | | **实现复杂** | 简单(Object.assign等) | 复杂(需递归/序列化) | | **适用场景** | 简单对象、无嵌套引用 | 复杂嵌套对象、需完全隔离 | #### 三、内存模型图解 ``` 浅拷贝内存模型: 原始对象 ───┬───> 基本类型值 └───> 引用类型地址 ───> [共享内存块] 拷贝对象 ───┘ 深拷贝内存模型: 原始对象 ───> 基本类型值 └──> 引用类型地址 ───> [独立内存块A] 拷贝对象 ───> 复制的基本类型值 └──> 新引用地址 ─────> [独立内存块B](内容与A相同) ``` #### 四、关键应用场景 1. **必须使用深拷贝的情况**: - 需要完全隔离的配置对象 - 包含状态的历史记录保存 - 跨线程/进程数据传输(如Web Worker) - 避免循环引用导致的无限递归[^3] 2. **浅拷贝的适用场景**: - 简单数据传输(无嵌套引用) - 高性能要求的临时对象复制 - 不可变对象(如String, Number等包装类) #### 五、深拷贝实现方案 1. **JSON序列化法**(简易但有限制): ```javascript function simpleDeepClone(obj) { return JSON.parse(JSON.stringify(obj)); } // 限制:无法复制函数、undefined、循环引用 ``` 2. **递归克隆法**(通用实现): ```javascript function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (map.has(obj)) return map.get(obj); // 解决循环引用 const clone = Array.isArray(obj) ? [] : {}; map.set(obj, clone); for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key], map); } } return clone; } ``` 3. **特殊对象处理**(补充方案): ```javascript // 处理Date/RegExp等内置对象 if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); ``` > **本质区别**: > 浅拷贝如同复印名片——复印件原件指向同一个电话号码(共享资源);深拷贝如同新建电话号码——双方完全独立通信[^2][^4]。选择取决于是否需要真正的数据隔离。 --- ### 相关问题 1. 如何处理深拷贝过程中的循环引用问题? 2. JSON序列化实现深拷贝有哪些局限性?如何解决? 3. 在Java/Python等语言中如何实现深拷贝? 4. 深拷贝浅拷贝在内存管理上有哪些性能差异? 5. 如何为包含函数的对象实现深拷贝
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值