1. copy复制对象

copy模块包括两个函数copy()和deepcopy(),用于复制现有的对象。

1.1 浅副本

copy()创建的浅副本(shallow copy)是一个新容器,其中填充了原对象内容的引用。建立list对象的一个浅副本时,会构造一个新的list,并将原对象的元素追加到这个list。

import copy
import functools @functools.total_ordering
class MyClass: def __init__(self, name):
self.name = name def __eq__(self, other):
return self.name == other.name def __gt__(self, other):
return self.name > other.name a = MyClass('a')
my_list = [a]
dup = copy.copy(my_list) print(' my_list:', my_list)
print(' dup:', dup)
print(' dup is my_list:', (dup is my_list))
print(' dup == my_list:', (dup == my_list))
print('dup[0] is my_list[0]:', (dup[0] is my_list[0]))
print('dup[0] == my_list[0]:', (dup[0] == my_list[0]))

作为一个浅副本,并不会复制MyClass实例,所以dup列表中的引用会指向my_list中相同的对象。

1.2 深副本

deepcopy()创建的深副本是一个新容器,其中填充了原对象内容的副本。要建立一个list的深副本,会构造一个新的list,复制原列表的元素,然后将这些副本追加到新列表。

将前例中的copy()调用替换为deepcopy(),可以清楚地看出输出的不同。

import copy
import functools @functools.total_ordering
class MyClass: def __init__(self, name):
self.name = name def __eq__(self, other):
return self.name == other.name def __gt__(self, other):
return self.name > other.name a = MyClass('a')
my_list = [a]
dup = copy.deepcopy(my_list) print(' my_list:', my_list)
print(' dup:', dup)
print(' dup is my_list:', (dup is my_list))
print(' dup == my_list:', (dup == my_list))
print('dup[0] is my_list[0]:', (dup[0] is my_list[0]))
print('dup[0] == my_list[0]:', (dup[0] == my_list[0]))

列表的第一个元素不再是相同的对象引用,不过比较这两个对象时,仍认为它们是相等的。

1.3 定制复制行为

可以使用特殊方法__copy__()和__deepcopy__()来控制如何建立副本。

调用__copy__()而不提供任何参数,这会返回对象的一个浅副本。

调用__deepcopy__(),并提供一个备忘字典,这会返回对象的一个深副本。所有需要深复制的成员属性都要连同备忘字典传递到copy.deepcopy()以控制递归(备忘字典将在后面更详细地解释)。

import copy
import functools @functools.total_ordering
class MyClass: def __init__(self, name):
self.name = name def __eq__(self, other):
return self.name == other.name def __gt__(self, other):
return self.name > other.name def __copy__(self):
print('__copy__()')
return MyClass(self.name) def __deepcopy__(self, memo):
print('__deepcopy__({})'.format(memo))
return MyClass(copy.deepcopy(self.name, memo)) a = MyClass('a') sc = copy.copy(a)
dc = copy.deepcopy(a)

备忘字典用于跟踪已复制的值,以避免无限递归。

1.4 深副本中的递归

为了避免复制递归数据结构可能带来的问题,deepcopy()使用了一个字典来跟踪已复制的对象。将这个字典传入__deepcopy__()方法,这样在该方法中也可以检查这个字典。

import copy

class Graph:

    def __init__(self, name, connections):
self.name = name
self.connections = connections def add_connection(self, other):
self.connections.append(other) def __repr__(self):
return 'Graph(name={}, id={})'.format(
self.name, id(self)) def __deepcopy__(self, memo):
print('\nCalling __deepcopy__ for {!r}'.format(self))
if self in memo:
existing = memo.get(self)
print(' Already copied to {!r}'.format(existing))
return existing
print(' Memo dictionary:')
if memo:
for k, v in memo.items():
print(' {}: {}'.format(k, v))
else:
print(' (empty)')
dup = Graph(copy.deepcopy(self.name, memo), [])
print(' Copying to new object {}'.format(dup))
memo[self] = dup
for c in self.connections:
dup.add_connection(copy.deepcopy(c, memo))
return dup root = Graph('root', [])
a = Graph('a', [root])
b = Graph('b', [a, root])
root.add_connection(a)
root.add_connection(b) dup = copy.deepcopy(root)

Graph类包含一些基本的有向图方法。可以利用一个名和一个列表(包含已连接的现有节点)初始化一个graph实例。add_connection()方法用于建立双向连接。深复制操作符也用到了这个方法。

__deepcopy__()方法将打印消息来显示这个方法是如何调用的,并根据需要管理备忘字典内容。它不是复制整个连接列表,而是创建一个新列表,再把各个连接的副本追加到这个列表。这样可以确保复制各个新节点时会更新备忘字典,而避免递归问题或多于的节点副本。与前面一页,完成时会返回复制的对象。

Python3标准库:copy复制对象的更多相关文章

  1. Python3标准库:weakref对象的非永久引用

    1. weakref对象的非永久引用 weakref模块支持对象的弱引用.正常的引用会增加对象的引用数,并避免它被垃圾回收.但结果并不总是如期望中的那样,比如有时可能会出现一个循环引用,或者有时需要内 ...

  2. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  3. Python3 标准库

    Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...

  4. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  5. 比较两个文件的异同Python3 标准库difflib 实现

    比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...

  6. 1.Python3标准库--前戏

    Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...

  7. python023 Python3 标准库概览

    Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...

  8. python3标准库总结

    Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...

  9. 3.Python3标准库--数据结构

    (一)enum:枚举类型 import enum ''' enum模块定义了一个提供迭代和比较功能的枚举类型.可以用这个为值创建明确定义的符号,而不是使用字面量整数或字符串 ''' 1.创建枚举 im ...

随机推荐

  1. @ControllerAdvice实现优雅地处理异常

    @ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理.最常用的 ...

  2. Math.Atan2 方法

    返回正切值为两个指定数字的商的角度. public static double Atan2 ( double y, double x ) 参数 y 点的 y 坐标. x 点的 x 坐标. 返回值 角  ...

  3. 返回数据中提取数据的方法(JSON数据取其中某一个值的方法)

    返回数据中提取数据的方法 比如下面的案例是,取店铺名称 接口返回数据如下: {"Code":0,"Msg":"ok","Data& ...

  4. AI初探

    看东西应该记笔记,不然如过眼云烟,如只逛商场,不买东西,不留下带走什么,就是浪费时间,没有收获,仅此开始,定期梳理看过的东西. 人工智能的目的是什么呢? 答:让机器表现得更像人类,甚至在某些技能上超越 ...

  5. CTF--HTTP服务--SSI注入

    开门见山 1. 扫描靶场ip,发现VM 192.168.31.160 2. 扫描主机服务信息和服务版本 3. 快速扫描靶场全部信息 4. 探测开放的http的敏感信息 5. 再用dirb扫描敏感页面 ...

  6. Git详解之协议/速度/安全

    协议概述 Git共享服务的实现方式大致分为四种:文件共享类型.git类型.ssh类型.http类型: 本地协议 本地协议:文件共享类型,是对Git项目,通过文件共享的方式:如NFS.FTP.samba ...

  7. 深入SpringMVC注解

    原文链接:https://blog.csdn.net/chenpeng19910926/article/details/70837756 @Controller 在SpringMVC 中提供了一个非常 ...

  8. chrome浏览器无法开启同步功能 request cancel

    解决办法 添加代理规则*.googleapis.com

  9. IDEA | Dot Executable: null..No dot executable found

    背景 今天想在IDEA上打开.puml后缀的类图,发现IDEA并不能识别,但是正常的时序图却能正常打开,打开类图就报如下错误: 解决方案 经排查,idea的plantuml插件默认只支持时序图,类图还 ...

  10. 面试总结 | Linux后台开发不得不看的知识点(给进军bat的你!)

    目录 一 自我介绍 二 面试情况 三 相关知识点汇总 1 c/c++相关 2 计算机网络 3 数据结构相关 4 数据库相关 5 操作系统 6 Linux基础知识及应用编程(后台必备!) 7 大数问题 ...