Python之旅——列表深浅拷贝

本文深入探讨了Python中列表的深浅拷贝概念,通过实例展示了普通列表拷贝、list生成表达式以及使用copy库的拷贝方法。强调了当列表包含嵌套列表时,浅拷贝的局限性,并提供了递归和使用`copy.deepcopy()`进行深拷贝的解决方案。总结了浅拷贝与深拷贝的区别,并提醒在程序设计中合理选择拷贝方式的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

列表深浅拷贝

将列表中的值,拷贝到的容器。

先思考一下,采用下列方式,是否能达到拷贝列表的目的?

nums = [1, 2, 3]
copied_nums = nums

print(f"nums={nums}")
print(f"copied_nums={copied_nums}")

代码输出:

nums=[1, 2, 3]
copied_nums=[1, 2, 3]

上述仅仅是,将copied_nums变量与nums变量都指向了相同的列表对象。如若不信,请查看下列代码:

nums = [1, 2, 3]
copied_nums = nums

copied_nums[2] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x27968a65208], val:[1, 2, 1010]
copied_nums addr[0x27968a65208], val:[1, 2, 1010]

普通列表拷贝

  • list对象构造
  • list生成表达式
  • 使用copy库

list对象构造

nums = [1, 2, 3]
copied_nums = list(nums)    # list 对象构造方式

copied_nums[2] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x1d53e2f5208], val:[1, 2, 3]
copied_nums addr[0x1d540189a88], val:[1, 2, 1010]

list生成表达式

nums = [1, 2, 3]
copied_nums = [num for num in nums]     # list生成表达式

copied_nums[2] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x14dd8165208], val:[1, 2, 3]
copied_nums addr[0x14dd8165408], val:[1, 2, 1010]

copy库

import copy

nums = [1, 2, 3]
copied_nums = copy.copy(nums)     # copy库拷贝

copied_nums[2] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x2329f3143c8], val:[1, 2, 3]
copied_nums addr[0x2329f2f9ac8], val:[1, 2, 1010]

嵌套列表拷贝

若列表中嵌套列表,上述三种方式(浅拷贝)将不再可用。采用list对象构造方式,可自行尝试上述介绍的其他方式:

nums = [1, 2, 3, [4, 5, 6]]
copied_nums = list(nums)     # list 对象构造方式

copied_nums[3][1] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x29ec7dc5408], val:[1, 2, 3, [4, 1010, 6]]
copied_nums addr[0x29ec8149b48], val:[1, 2, 3, [4, 1010, 6]]

当然,可采用2层的for语句的方式,实现拷贝嵌套一层的列表。但是,如果是嵌套层级太深,那就需要太多的for语句,同时还依赖于每个列表成员的数据类型。

递归方式

def deep_copy_list(nums):
    '''
    仅支持int的列表成员和嵌套列表的拷贝
    '''
    items = []
    for num in nums:
        if isinstance(num, int):
            items.append(num)
        else:
            items.append(deep_copy_list(num))
    return items

nums = [1, 2, 3, [4, 5, 6]]
copied_nums = deep_copy_list(nums)     # 递归调用拷贝函数

copied_nums[3][1] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x22f87b753c8], val:[1, 2, 3, [4, 5, 6]]
copied_nums addr[0x22f87ef95c8], val:[1, 2, 3, [4, 1010, 6]]

使用库函数

使用自定义的拷贝函数,需要比较完善的考虑,支持各种数据类型和列表的嵌套。不过,python中有提供现成的深拷贝库函数:

import copy

nums = [1, 2, 3, [4, 5, 6]]
copied_nums = copy.deepcopy(nums) 

copied_nums[3][1] = 1010

print(f"nums addr[0x{id(nums):x}], val:{nums}")
print(f"copied_nums addr[0x{id(copied_nums):x}], val:{copied_nums}")

代码输出:

nums addr[0x15cad719c48], val:[1, 2, 3, [4, 5, 6]]
copied_nums addr[0x15cad719c88], val:[1, 2, 3, [4, 1010, 6]]

总结

  • 浅拷贝:仅拷贝集合最外层的成员值,和嵌套的集合对象的引用,到新的集合对象。
  • 深拷贝:嵌套集合中的所有对象都将被拷贝到新的集合对象。

注:
一般情况下,仅用到浅拷贝;若使用到深拷贝,那表明程序框架需要再考虑。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值