深入理解python特性_深入理解Python特性(7)

克隆对象

Python中的赋值语句不会创建对象的副本,只是将名称绑定到对象上。对于不可变对象也是如此。但为了处理可变对象或可变对象集合,需要一种方法来创建这些对象的“真实副本”或“克隆体”。从本质上讲,你有时候需要用到对象的副本,以便修改副本时不会改动本体。先来看如何复制Python的内置容器(collection)。Python的内置可变容器,如列表、字典和集合,调用对应的工厂函数就能完成复制:

bd01e534b6bc460dc6a347c79f65df45.png

但用这种方法无法复制自定义对象,且最重要的是这种方法只创建浅副本。对于像列表、字典和集合这样的复合对象,浅复制和深复制之间有重要的区别。 浅复制是指构建一个新的容器对象,然后填充原对象中子对象的引用。本质上浅复制只执行一层,复制过程不会递归,因此不会创建子对象的副本。 深复制是递归复制,首先构造一个新的容器对象,然后递归的填充原始对象中子对象的副本。这种方式会遍历整个对象树,以此来创建原对象及其所有子项的完全独立体的副本。

0f5bcb503be4de0c68a64efe2085579c.png

先尝试向原对象(xs)添加一个新列表,然后查看这个改动是否影响了副本(ys ):

b44078f037f574b908bf0c6b07880ac4.png

从中可以看出,修改浅复制的列表完全不会影响副本。但由于前面只创建了原列表的浅副本,所以ys仍然含有xs子对象的引用,这些子对象没有复制,只是在ys中再次引用。因此在修改xs中的子对象时,这些改动也会反映在ys中——因为两个列表共享相同的子对象。这个副本是仅含有一层的浅复制:

ae609b4d433e7147906a9fbf96670950.png

修改了xs中的子对象,ys相对应的子对象也发生变化。 制作深副本

使用copy模块中的deepcopy函数创建深副本:

49092a7f94f3adce6843518d5256d860.png

现在原对象和副本是完全独立的。复制过程中递归复制了xs,包括它的所有子对象。

By the way, copy.copy()函数会创建对象的浅副本。

在代码中,copy.copy()可以清楚地表明创建的是浅副本。但对于内置容器,只需要使用list、dict和set这样的工厂函数就能创建副本,这种方式更具Python特色。

复制任意对象

copy模块中的copy和deepcopy函数可以复制任意对象。

首先定义一个2D 点类:

52cdec2030e8f32c36dca90fc4076ea3.png

由于点对象使用不可变类型(int)作为坐标,浅深复制之间并没有区别。下面来看一个更复杂的例子, 2D矩形类:

bb9a5ca25fd9ffbc58f2845e8095902d.png

86d0cfa2b6799a455e2c55c9703c82ea.png

可以看到修改原对象的子对象,浅复制的副本相应发生变化。

而深复制则不会:

708f54f7f8c2fc861f2c156664a7e1aa.png

关键要点:

  • 创建的浅副本不会克隆子对象,因此副本和原对象并不完全独立。

  • 对象的深副本将递归克隆子对象。副本完全独立于原对象,但创建         深副本的速度比较慢,因为发生了递归。

  • 使用copy模块可以复制任意对象(包括自定义对象)。

本节内容结束,下节见!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值