python中的浅拷贝和深拷贝

概念与区别

  • 浅拷贝通常只复制对象本身。只拷贝原数据的首地址,通过首地址读取内容。
  • 深拷贝,新开一片内存把原数据都拷贝过来了,所有数据都是独立的新实例。

浅拷贝:copy.copy()

深拷贝:copy.deepcopy()

假设目前有一组数据,结构有两层,测试结果如下

浅拷贝
内层数据类型外层数据类型数据的地址是否改变
可变 可变 外变  内不变
不可变可变外变 内不变
不可变不可变外不变 内不变
可变不可变外不变 内不变
深拷贝
内层数据类型外层数据类型数据的地址是否改变
可变 可变 外变 内变
不可变可变 外变 内不变
不可变不可变外不变 内不变
可变 不可变外变 内变

小结:

对于浅拷贝,不管内层数据类型,浅拷贝都不会改变内层地址;外层数据地址随原数据外层数据类型改变

对于深拷贝,内层数据为可变,深拷贝后内外层地址都会改变;内层数据类型为不可变,深拷贝后内层不变,外层随原数据类型改变

深拷贝可能遇到的问题

深拷贝可能会遇到两个问题:一是一个对象如果直接或间接的引用了自身,会导致无休止的递归拷贝;二是深拷贝可能对原本设计为多个对象共享的数据也进行拷贝。

列表、字典实现深拷贝

列表、字典如何实现拷贝操作以及如何通过序列化和反序列的方式实现深拷贝

deepcopy函数的本质其实就是对象的一次序列化和一次返回序列化

import pickle


author1 = {"1": "1", "2": "2", "3": "3", "4": [5, 6]}

# pickle序列化
pickle_str = pickle.dumps(author1)
print("pickle=>\n", pickle_str)

# pickle字符串反序列化
author3 = pickle.loads(pickle_str)


print("\n",
      author1, "\n",
      author3, "\n",
    )

设计模式中的原型模式

列表的切片操作[:]相当于实现了列表对象的浅拷贝,而字典的copy方法可以实现字典对象的浅拷贝。对象拷贝其实是更为快捷的创建对象的方式。在Python中,通过构造器创建对象属于两阶段构造,首先是分配内存空间,然后是初始化。在创建对象时,我们也可以基于“原型”对象来创建新对象,通过对原型对象的拷贝(复制内存)就完成了对象的创建和初始化,这种做法更加高效,这也就是设计模式中的原型模式。在Python中,我们可以通过元类的方式来实现原型模式,代码如下所示。

import copy


class PrototypeMeta(type):
    """实现原型模式的元类"""

    def __init__(cls, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 为对象绑定clone方法来实现对象拷贝
        cls.clone = lambda self, is_deep=True: \
            copy.deepcopy(self) if is_deep else copy.copy(self)


class Person(metaclass=PrototypeMeta):
    pass


p1 = Person()
p2 = p1.clone()                 # 深拷贝
p3 = p1.clone(is_deep=False)    # 浅拷贝

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值