导航菜单

  • 1.VSCode开发
  • 2.什么是Python?
  • 3.请详细解释Python代码的执行过程
  • 4.请详细解释解释型语言与编译型语言的主要区别
  • 5.你知道哪些Python的编码规范?
  • 6.数据类型
  • 7.Python中如何声明多个变量并赋值
  • 8.Python有哪些内置数据结构
  • 9.!=和is not运算符有什么区别?
  • 10.进制
  • 11.编码
  • 12.print
  • 13.Python中break、continue、pass有什么作用?
  • 14.namedtuple有什么作用?
  • 15.Python的range函数如何运用?
  • 16.Python中join()和split()函数有什么区别?
  • 17.Python中如何将字符串转换为小写?
  • 18.Python中如何删除字符串中的前置空格?
  • 19.Python中如何使用索引反转字符串
  • 20.什么是Python的成员运算符?
  • 21.请详细说明Python中逻辑运算符(`and`、`or`、`not`)
  • 22.什么是Python的关系运算符?
  • 23.什么是Python的赋值和算术运算符?请详细说明赋值运算符、算术运算符的种类、使用方法、优先级规则。
  • 24.请详细解释Python中整数除法、取模运算和幂运算三个运算符。
  • 25.如何在Python中表示和转换不同进制的数字
  • 26.什么是Python的位运算符?
  • 27.请详细说明Python中三元表达式(Ternary Expression)的工作原理
  • 28.Python中如何实现switch语句?
  • 29.什么是Python的负索引?
  • 30.Python中如何实现字符串替换操作?
  • 31.Python中append、insert和extend有什么区别?
  • 32.请详细说明Python中`enumerate()`函数的作用
  • 33.Python中remove、del和pop有什么区别?
  • 34.Python中如何更改列表元素的数据类型?
  • 35.请详细说明Python中列表(list)和元组(tuple)的区别
  • 36.什么是Python元组的解封装?
  • 37.详细说明Python字典
  • 38.Python中KeyError、TypeError和ValueError有什么区别?
  • 39.请详细解释Python中`read()`、`readline()`和`readlines()`三种文件读取方法
  • 40.Python中iterable、iterator和generator的区别与联系
  • 41.Python中如何读取大文件?
  • 42.请详细解释Python中浅拷贝(shallow copy)和深拷贝(deep copy)的区别
  • 43.什么是Python的Lambda函数?
  • 44.Python中的reduce函数有什么作用?
  • 45.Python的zip函数有什么作用?
  • 46.请详细解释Python中`any()`和`all()`内置函数的作用
  • 47.为什么Python中没有函数重载?
  • 48.请介绍Python中变量的作用域(Scope)?
  • 49.什么是Python的闭包
  • 50.请详细说明Python中的内存管理机制
  • 51.请详细说明Python程序退出时内存的释放情况
  • 52.Python中是否有严格意义上的main函数?
  • 53.什么是Python的pickling和unpickling?
  • 54.什么是Python的猴子补丁(monkey patching)?
  • 55.什么是Python的鸭子类型(Duck Typing)
  • 56.什么是Python中的面向对象编程
  • 57.Python是否支持多重继承
  • 58.请详细说明Python3中装饰器的用法
  • 59.什么是Python中的模块和包?
  • 60.你使用过哪些Python标准库模块?
  • 61.你知道哪些Python魔术方法
  • 62.讲一下Python多线程、多进程和线程池
  • 63.如何分析Python代码的执行性能?
  • 64.pip
  • 65.pip-m
  • 67.uv
  • utf8
  • ast
  • dis
  • 尾递归
  • MethodType
  • 请详细解释Python中浅拷贝和深拷贝的区别、工作原理和实现方式
  • 1. 概念定义
    • 1.1 浅拷贝(Shallow Copy)
    • 1.2 深拷贝(Deep Copy)
  • 2. 工作原理
    • 2.1 浅拷贝的工作原理
    • 2.2 深拷贝的工作原理
  • 3. 实现方式
    • 3.1 copy
    • 3.2 部分内置类型的专有浅拷贝方式
    • 3.3 浅拷贝和深拷贝的适用场景
  • 4. 详细行为分析
    • 4.1 嵌套列表的拷贝行为
    • 4.2 自定义类的拷贝行为
  • 5. 循环引用问题
  • 6.实现
  • 7. 总结

请详细解释Python中浅拷贝和深拷贝的区别、工作原理和实现方式 #

1. 概念定义 #

在Python中,当我们复制一个对象时,实际上是在创建一个新对象。根据复制的深度,Python提供了两种主要的复制方式:浅拷贝和深拷贝。

1.1 浅拷贝(Shallow Copy) #

浅拷贝会创建一个新的对象,但对于原始对象中包含的嵌套对象(如列表中的列表、字典中的字典等),它不会递归地复制这些嵌套对象,而是复制它们的引用。这意味着新对象和原始对象会共享相同的嵌套子对象。

1.2 深拷贝(Deep Copy) #

深拷贝会创建一个全新的对象,并且会递归地复制原始对象中所有层级的嵌套对象。这意味着新对象和原始对象是完全独立的,它们不共享任何嵌套子对象。

2. 工作原理 #

2.1 浅拷贝的工作原理 #

当执行浅拷贝时,Python会执行以下操作:

  • 顶层对象:创建一个新的顶层容器对象(例如,一个新的列表或字典)
  • 嵌套对象:对于原始对象中的元素,如果是不可变类型(如数字、字符串、元组),则直接复制其值;如果是可变类型(如列表、字典、集合),则复制其引用

2.2 深拷贝的工作原理 #

当执行深拷贝时,Python会执行以下操作:

  • 所有层级对象:递归地遍历原始对象及其所有嵌套子对象
  • 独立副本:为每个遇到的对象(包括所有嵌套的可变对象)都创建一个全新的独立副本

3. 实现方式 #

Python 标准库中的 copy 模块专门用于对象的“浅拷贝”和“深拷贝”。

  • copy.copy(obj):返回对象 obj 的浅拷贝。
  • copy.deepcopy(obj):返回对象 obj 的深拷贝。

3.1 copy #

import copy

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

# 修改嵌套对象
a[2][0] = 999

print('a:', a)   # [1, 2, [999, 4]]
print('b:', b)   # [1, 2, [999, 4]]  # 受影响(嵌套对象共享)
print('c:', c)   # [1, 2, [3, 4]]    # 不受影响(嵌套对象已复制)

要点总结:

  • copy.copy() 只复制最外层对象,新对象内部的可变对象仍与原对象共享内存。
  • copy.deepcopy() 会递归复制所有层级,实现完全独立。

3.2 部分内置类型的专有浅拷贝方式 #

  • 列表:lst.copy() 或 lst[:]
  • 字典:dict.copy()
  • 集合:set.copy()

示例:

lst1 = [[1], [2, 3]]
lst2 = lst1[:]         # 等价于 copy.copy(lst1)
lst1[0][0] = 99
print(lst2)   # [[99], [2, 3]]

这种方式只适用于浅拷贝。

3.3 浅拷贝和深拷贝的适用场景 #

浅拷贝适用:

  • 只需要复制对象本身,对象内部的可变元素不需独立修改。
  • 操作的数据层级不深,或内部对象本身默认不会被修改。

深拷贝适用:

  • 需要对复杂嵌套结构的对象进行完全隔离副本时。
  • 任何对子对象的修改都不能影响原对象。

4. 详细行为分析 #

4.1 嵌套列表的拷贝行为 #

import copy

# 创建一个更复杂的嵌套结构
original_data = {
    'name': '张三',
    'age': 25,
    'hobbies': ['读书', '游泳', '编程'],
    'address': {
        'city': '北京',
        'district': '朝阳区'
    },
    'scores': [85, 92, 78]
}

# 执行浅拷贝
shallow_copy = copy.copy(original_data)

# 执行深拷贝
deep_copy = copy.deepcopy(original_data)

print("=== 修改前的状态 ===")
print("原始数据:", original_data)
print("浅拷贝:", shallow_copy)
print("深拷贝:", deep_copy)

# 修改原始数据中的嵌套对象
original_data['hobbies'].append('音乐')
original_data['address']['city'] = '上海'
original_data['scores'][0] = 95

print("\n=== 修改后的状态 ===")
print("原始数据:", original_data)
print("浅拷贝:", shallow_copy)
print("深拷贝:", deep_copy)

# 检查对象身份
print("\n=== 对象身份检查 ===")
print("原始hobbies id:", id(original_data['hobbies']))
print("浅拷贝hobbies id:", id(shallow_copy['hobbies']))
print("深拷贝hobbies id:", id(deep_copy['hobbies']))
print("原始和浅拷贝hobbies是否相同:", original_data['hobbies'] is shallow_copy['hobbies'])
print("原始和深拷贝hobbies是否相同:", original_data['hobbies'] is deep_copy['hobbies'])

4.2 自定义类的拷贝行为 #

import copy

class Person:
    def __init__(self, name, age, hobbies):
        # 初始化Person对象
        self.name = name
        self.age = age
        self.hobbies = hobbies  # 这是一个可变列表

    def __repr__(self):
        # 定义对象的字符串表示
        return f"Person(name='{self.name}', age={self.age}, hobbies={self.hobbies})"

# 创建Person对象
person1 = Person('李四', 30, ['读书', '游泳'])

# 执行浅拷贝
shallow_person = copy.copy(person1)

# 执行深拷贝
deep_person = copy.deepcopy(person1)

print("=== 修改前的状态 ===")
print("原始对象:", person1)
print("浅拷贝对象:", shallow_person)
print("深拷贝对象:", deep_person)

# 修改原始对象的属性
person1.name = '王五'
person1.age = 35
person1.hobbies.append('音乐')

print("\n=== 修改后的状态 ===")
print("原始对象:", person1)
print("浅拷贝对象:", shallow_person)
print("深拷贝对象:", deep_person)

# 检查hobbies列表的身份
print("\n=== hobbies列表身份检查 ===")
print("原始hobbies id:", id(person1.hobbies))
print("浅拷贝hobbies id:", id(shallow_person.hobbies))
print("深拷贝hobbies id:", id(deep_person.hobbies))

5. 循环引用问题 #

import copy

# 创建循环引用的对象
class Node:
    def __init__(self, value):
        self.value = value
        self.parent = None
        self.children = []

    def add_child(self, child):
        # 添加子节点
        child.parent = self
        self.children.append(child)

# 创建节点
root = Node('根节点')
child1 = Node('子节点1')
child2 = Node('子节点2')

# 建立循环引用
root.add_child(child1)
root.add_child(child2)

print("原始对象创建成功")
print(f"根节点子节点数: {len(root.children)}")
print(f"子节点1的父节点: {child1.parent.value}")

try:
    # 尝试深拷贝循环引用对象
    deep_copy = copy.deepcopy(root)
    print("深拷贝成功(Python能处理循环引用)")
    print(f"深拷贝根节点子节点数: {len(deep_copy.children)}")
    print(f"深拷贝子节点1的父节点: {deep_copy.children[0].parent.value}")
except Exception as e:
    print(f"深拷贝失败: {e}")

6.实现 #

# 实现浅拷贝函数
def shallow_copy(obj):
    """实现浅拷贝"""
    # 如果对象是列表,则返回一个新列表,元素为原有元素(引用)
    if isinstance(obj, list):
        return [item for item in obj]
    # 如果对象是元组,则返回一个新元组,元素为原有元素(引用)
    elif isinstance(obj, tuple):
        return tuple(item for item in obj)
    # 如果对象是字典,则返回一个新字典,键值对均为原有的(引用)
    elif isinstance(obj, dict):
        return {key: value for key, value in obj.items()}
    # 如果对象是集合,则返回一个新集合,元素为原有元素(引用)
    elif isinstance(obj, set):
        return {item for item in obj}
    else:
        # 对于其他类型,返回原对象(引用)
        return obj

# 实现深拷贝函数
def deep_copy(obj):
    """实现深拷贝"""
    # 如果对象是列表,递归深拷贝每个元素
    if isinstance(obj, list):
        return [deep_copy(item) for item in obj]
    # 如果对象是元组,递归深拷贝每个元素
    elif isinstance(obj, tuple):
        return tuple(deep_copy(item) for item in obj)
    # 如果对象是字典,对每个value递归深拷贝
    elif isinstance(obj, dict):
        return {key: deep_copy(value) for key, value in obj.items()}
    # 如果对象是集合,递归深拷贝每个元素
    elif isinstance(obj, set):
        return {deep_copy(item) for item in obj}
    else:
        # 对于基本类型(int, str, float等),直接返回
        return obj

# 定义测试用的数据
a = [1, 2, [3, 4]]
# 对a进行浅拷贝,得到b
b = shallow_copy(a)
# 对a进行深拷贝,得到c
c = deep_copy(a)

# 打印原始数据
print("原始数据:")
print(f"a = {a}")
print(f"a的id: {id(a)}")
print(f"a[2]的id: {id(a[2])}")

# 打印浅拷贝的结果
print("\n浅拷贝结果:")
print(f"b = {b}")
print(f"b的id: {id(b)}")
print(f"b[2]的id: {id(b[2])}")

# 打印深拷贝的结果
print("\n深拷贝结果:")
print(f"c = {c}")
print(f"c的id: {id(c)}")
print(f"c[2]的id: {id(c[2])}")

# 打印修改的测试
print("\n修改测试:")
# 修改原始数据的第一个元素
a[0] = 999
# 修改原始数据嵌套列表中的第一个元素
a[2][0] = 888

# 打印修改后的a, b, c
print(f"修改后 a = {a}")
print(f"修改后 b = {b}")
print(f"修改后 c = {c}")

# 验证a[2], b[2], c[2]是否为同一个对象
print("\n验证:")
print(f"a[2] 和 b[2] 是同一个对象: {a[2] is b[2]}")
print(f"a[2] 和 c[2] 是同一个对象: {a[2] is c[2]}")
print(f"b[2] 和 c[2] 是同一个对象: {b[2] is c[2]}")
def deepCopy(obj, memo=None):
    # 初始化备忘录,用于记录已拷贝的对象
    if memo is None:
        memo = {}

    # 如果对象已经被拷贝过,直接返回拷贝后的对象
    if id(obj) in memo:
        return memo[id(obj)]

    # 如果对象是列表
    if isinstance(obj, list):
        copy_list = []
        memo[id(obj)] = copy_list  # 在递归前记录,防止循环引用
        copy_list.extend(deepCopy(item, memo) for item in obj)
        return copy_list

    # 如果对象是元组
    elif isinstance(obj, tuple):
        copy_tuple = tuple(deepCopy(item, memo) for item in obj)
        memo[id(obj)] = copy_tuple
        return copy_tuple

    # 如果对象是字典
    elif isinstance(obj, dict):
        copy_dict = {}
        memo[id(obj)] = copy_dict  # 在递归前记录,防止循环引用
        for key, value in obj.items():
            copy_dict[deepCopy(key, memo)] = deepCopy(value, memo)
        return copy_dict

    # 如果对象是集合
    elif isinstance(obj, set):
        copy_set = set()
        memo[id(obj)] = copy_set  # 在递归前记录,防止循环引用
        for item in obj:
            copy_set.add(deepCopy(item, memo))
        return copy_set

    # 如果对象是类的实例
    elif hasattr(obj, "__dict__"):
        # 创建新实例,但不调用__init__
        copy_obj = obj.__class__.__new__(obj.__class__)
        memo[id(obj)] = copy_obj  # 在递归前记录,防止循环引用

        # 拷贝所有属性
        for attr_name, attr_value in obj.__dict__.items():
            setattr(copy_obj, attr_name, deepCopy(attr_value, memo))

        # 如果有自定义的__deepcopy__方法,优先使用
        if hasattr(obj, "__deepcopy__"):
            return obj.__deepcopy__(memo)

        return copy_obj

    # 对于不可变的基本类型,直接返回
    else:
        return obj


class Node:
    def __init__(self, value):
        self.value = value
        self.parent = None
        self.children = []

    def add_child(self, child):
        child.parent = self
        self.children.append(child)

    def __deepcopy__(self, memo):
        # 如果已经在备忘录中,直接返回
        if id(self) in memo:
            return memo[id(self)]

        # 创建新实例
        copy_obj = self.__class__.__new__(self.__class__)
        memo[id(self)] = copy_obj

        # 手动拷贝属性,避免无限递归
        copy_obj.value = deepCopy(self.value, memo)
        copy_obj.parent = deepCopy(self.parent, memo)
        copy_obj.children = deepCopy(self.children, memo)

        return copy_obj


# 测试代码
if __name__ == "__main__":
    # 测试普通类的深拷贝
    root = Node("根节点")
    child1 = Node("子节点1")
    child2 = Node("子节点2")
    root.add_child(child1)
    root.add_child(child2)

    print("原始对象:")
    print(f"root id: {id(root)}")
    print(f"root.children: {[child.value for child in root.children]}")
    print(f"child1.parent.value: {child1.parent.value}")

    print("\n深拷贝后:")
    deep_copy = deepCopy(root)
    print(f"deep_copy id: {id(deep_copy)}")
    print(f"deep_copy.children: {[child.value for child in deep_copy.children]}")
    print(f"deep_copy.children[0].parent.value: {deep_copy.children[0].parent.value}")

    # 验证确实是深拷贝
    print(f"\n验证深拷贝:")
    print(f"root is deep_copy: {root is deep_copy}")
    print(
        f"root.children[0] is deep_copy.children[0]: {root.children[0] is deep_copy.children[0]}"
    )
    print(
        f"child1.parent is deep_copy.children[0].parent: {child1.parent is deep_copy.children[0].parent}"
    )

    # 测试循环引用
    print("\n测试循环引用:")
    node_a = Node("A")
    node_b = Node("B")
    node_a.add_child(node_b)
    node_b.add_child(node_a)  # 创建循环引用

    try:
        copied = deepCopy(node_a)
        print("循环引用拷贝成功")
        print(f"原始A的children[0].value: {node_a.children[0].value}")
        print(f"拷贝A的children[0].value: {copied.children[0].value}")
        print(f"原始B的children[0].value: {node_b.children[0].value}")
        print(f"拷贝B的children[0].value: {copied.children[0].children[0].value}")
    except RecursionError as e:
        print(f"循环引用拷贝失败: {e}")
function deepCopy(obj, memo = new Map()) {
  // If object is null or not an object, return directly
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // If object has already been copied, return the copy
  if (memo.has(obj)) {
    return memo.get(obj);
  }

  // Handle Date objects
  if (obj instanceof Date) {
    const copy = new Date(obj.getTime());
    memo.set(obj, copy);
    return copy;
  }

  // Handle RegExp objects
  if (obj instanceof RegExp) {
    const copy = new RegExp(obj);
    memo.set(obj, copy);
    return copy;
  }

  // Handle Array objects
  if (Array.isArray(obj)) {
    const copy = [];
    memo.set(obj, copy); // Record before recursion to handle circular references
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepCopy(obj[i], memo);
    }
    return copy;
  }

  // Handle Set objects
  if (obj instanceof Set) {
    const copy = new Set();
    memo.set(obj, copy); // Record before recursion to handle circular references
    for (const item of obj) {
      copy.add(deepCopy(item, memo));
    }
    return copy;
  }

  // Handle Map objects
  if (obj instanceof Map) {
    const copy = new Map();
    memo.set(obj, copy); // Record before recursion to handle circular references
    for (const [key, value] of obj) {
      copy.set(deepCopy(key, memo), deepCopy(value, memo));
    }
    return copy;
  }

  // Handle plain objects and class instances
  const copy = Object.create(Object.getPrototypeOf(obj));
  memo.set(obj, copy); // Record before recursion to handle circular references

  // Copy all properties including symbols
  const allKeys = [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)];
  for (const key of allKeys) {
    // Skip non-enumerable properties for simplicity, but you could include them if needed
    const descriptor = Object.getOwnPropertyDescriptor(obj, key);
    if (descriptor && (descriptor.enumerable || key === 'parent' || key === 'children')) {
      copy[key] = deepCopy(obj[key], memo);
    }
  }

  // If object has custom deepCopy method, use it
  if (typeof obj.__deepcopy__ === 'function') {
    return obj.__deepcopy__(memo);
  }

  return copy;
}

class Node {
  constructor(value) {
    this.value = value;
    this.parent = null;
    this.children = [];
  }

  addChild(child) {
    child.parent = this;
    this.children.push(child);
  }

  __deepcopy__(memo) {
    // If already in memo, return the copy
    if (memo.has(this)) {
      return memo.get(this);
    }

    // Create new instance
    const copyObj = Object.create(Object.getPrototypeOf(this));
    memo.set(this, copyObj);

    // Manually copy properties to avoid infinite recursion
    copyObj.value = deepCopy(this.value, memo);
    copyObj.parent = deepCopy(this.parent, memo);
    copyObj.children = deepCopy(this.children, memo);

    return copyObj;
  }
}

// Test code
function testDeepCopy() {
  // Test basic class deep copy
  const root = new Node("根节点");
  const child1 = new Node("子节点1");
  const child2 = new Node("子节点2");
  root.addChild(child1);
  root.addChild(child2);

  console.log("原始对象:");
  console.log(`root id: ${root}`);
  console.log(`root.children: ${root.children.map(child => child.value)}`);
  console.log(`child1.parent.value: ${child1.parent.value}`);

  console.log("\n深拷贝后:");
  const deepCopyObj = deepCopy(root);
  console.log(`deepCopy id: ${deepCopyObj}`);
  console.log(`deepCopy.children: ${deepCopyObj.children.map(child => child.value)}`);
  console.log(`deepCopy.children[0].parent.value: ${deepCopyObj.children[0].parent.value}`);

  // Verify it's actually a deep copy
  console.log(`\n验证深拷贝:`);
  console.log(`root === deepCopyObj: ${root === deepCopyObj}`);
  console.log(`root.children[0] === deepCopyObj.children[0]: ${root.children[0] === deepCopyObj.children[0]}`);
  console.log(`child1.parent === deepCopyObj.children[0].parent: ${child1.parent === deepCopyObj.children[0].parent}`);

  // Test circular references
  console.log("\n测试循环引用:");
  const nodeA = new Node("A");
  const nodeB = new Node("B");
  nodeA.addChild(nodeB);
  nodeB.addChild(nodeA); // Create circular reference

  try {
    const copied = deepCopy(nodeA);
    console.log("循环引用拷贝成功");
    console.log(`原始A的children[0].value: ${nodeA.children[0].value}`);
    console.log(`拷贝A的children[0].value: ${copied.children[0].value}`);
    console.log(`原始B的children[0].value: ${nodeB.children[0].value}`);
    console.log(`拷贝B的children[0].value: ${copied.children[0].children[0].value}`);
  } catch (e) {
    console.log(`循环引用拷贝失败: ${e}`);
  }

  // Test other data types
  console.log("\n测试其他数据类型:");

  // Test Date
  const originalDate = new Date('2023-01-01');
  const copiedDate = deepCopy(originalDate);
  console.log(`Date copied: ${originalDate.getTime() === copiedDate.getTime() && originalDate !== copiedDate}`);

  // Test Set
  const originalSet = new Set([1, 2, 3]);
  const copiedSet = deepCopy(originalSet);
  console.log(`Set copied: ${Array.from(originalSet).join(',') === Array.from(copiedSet).join(',') && originalSet !== copiedSet}`);

  // Test Map
  const originalMap = new Map([['key1', 'value1'], ['key2', 'value2']]);
  const copiedMap = deepCopy(originalMap);
  console.log(`Map copied: ${Array.from(originalMap.entries()).toString() === Array.from(copiedMap.entries()).toString() && originalMap !== copiedMap}`);
}

// Run tests
testDeepCopy();

7. 总结 #

Python中的深拷贝和浅拷贝是处理对象复制的重要概念:

  1. 浅拷贝:

    • 只复制顶层对象,嵌套对象共享引用
    • 性能开销较小
    • 适用于不包含可变嵌套对象的场景
  2. 深拷贝:

    • 递归复制所有层级的对象
    • 性能开销较大
    • 适用于需要完全独立副本的场景
  3. 选择原则:

    • 根据数据结构是否包含可变嵌套对象
    • 根据是否需要完全独立的数据副本
    • 考虑性能要求和内存使用
  4. 最佳实践:

    • 对于不可变对象,通常不需要拷贝
    • 对于包含可变嵌套对象的复杂结构,优先考虑深拷贝
    • 注意循环引用和不可拷贝对象的处理

访问验证

请输入访问令牌

Token不正确,请重新输入