Python3标准库:copy复制对象

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

原文地址:https://www.cnblogs.com/liuhui0308/p/12346847.html

时间: 2024-08-29 11:23:18

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

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

1. weakref对象的非永久引用 weakref模块支持对象的弱引用.正常的引用会增加对象的引用数,并避免它被垃圾回收.但结果并不总是如期望中的那样,比如有时可能会出现一个循环引用,或者有时需要内存时可能要删除对象的缓存.弱引用(weak reference)是一个不能避免对象被自动清理的对象句柄. 1.1 引用 对象的弱引用要通过ref类来管理.要获取原对象,可以调用引用对象. import weakref class ExpensiveObject: def __del__(self):

Python3标准库:shelve对象的持久存储

1. shelve对象的持久存储 不需要关系数据库时,可以用shelve模块作为持久存储Python对象的一个简单的选择.类似于字典,shelf按键访问.值将被pickled并写至由dbm创建和管理的数据库. 1.1 创建一个新shelf 使用shelve最简单的方法就是利用DbfilenameShelf类.它使用dbm存储数据.这个类可以直接使用,也可以通过调用shelve.open()来使用. import shelve with shelve.open('test_shelf.db') a

Python3标准库

文本 1. string:通用字符串操作 2. re:正则表达式操作 3. difflib:差异计算工具 4. textwrap:文本填充 5. unicodedata:Unicode字符数据库 6. stringprep:互联网字符串准备工具 7. readline:GNU按行读取接口 8. rlcompleter:GNU按行读取的实现函数 二进制数据 9. struct:将字节解析为打包的二进制数据 10. codecs:注册表与基类的编解码器 数据类型 11. datetime:基于日期与

4.Python3标准库--算法

(一)functools:管理函数的工具 import functools ''' functools模块提供了一些工具来管理或扩展和其他callable对象,从而不必完全重写 ''' 1.修饰符 from functools import partial ''' functools模块提供的主要工具就是partial类,可以用来包装一个有默认参数的callable对象. 得到的对象本身就是callable,可以把它看作是原来的参数. ''' # 举个栗子 def foo(name, age,

Python3标准库:hashlib密码散列

1. hashlib密码散列 hashlib模块定义了一个API来访问不同的密码散列算法.要使用一个特定的散列算法,可以用适当的构造器函数或new()来创建一个散列对象.不论使用哪个具体的算法,这些对象都使用相同的API. 1.1 散列算法 由于hashlib有OpenSSL提供“底层支持”,所以OpenSSL库提供的所有算法都可用,包括: md5 sha1 sha224 sha256 sha384 sha512 有些算法在所有平台上都可用,而有些则依赖于底层库.这两种算法分别由algorith

Python3标准库:selectors I/O多路复用抽象

1. selectors I/O多路复用抽象 selectors模块在select中平台特定的I/O监视函数之上提供了一个平台独立的抽象层. 1.1 操作模型 selectors中的API是基于事件的,与select中的poll()类似.它有多个实现,并且这个模块会自动设置别名DefaultSelector来指示对当前系统配置最为高效的一个实现.选择器对象提供了一些方法,可以指定在一个套接字上查找哪些事件,然后以一种平台独立的方式让调用者等待事件.注册对事件的兴趣会创建一个SelectorKey

Python3标准库:urllib.parse分解URL

1. urllib.parse分解URL urllib.parse模块提供了一些函数,可以管理URL及其组成部分,这包括将URL分解为组成部分以及由组成部分构成URL. 1.1 解析 urlparse()函数的返回值是一个ParseResult对象,其相当于一个包含6个元素的tuple. from urllib.parse import urlparse url = 'http://netloc/path;param?query=arg#frag' parsed = urlparse(url)

Python标准库05 存储对象 (pickle包,cPickle包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 谢谢reverland纠错 在之前对Python对象的介绍中 (面向对象的基本概念,面向对象的进一步拓展),我提到过Python"一切皆对象"的哲学,在Python中,无论是变量还是函数,都是一个对象.当Python运行时,对象存储在内存中,随时等待系统的调用.然而,内存里的数据会随着计算机关机和消失,如何将对象保存到文件,并储存在硬盘上呢? 计算机的内存中存储的是二进

2.Python3标准库--文本

(一)string:文本常量和模板 1.函数 import string ''' string模块在最早的Python版本中就已经有了.以前这个模块中提供的很多函数已经移植到str对象中,不过这个模块仍然保留了很多有用的常量和类来处理str对象 ''' # 函数capwords会把一个字符串中的所有单词的首字母变成大写 s = "when i was young, i'd listen to the radio" print(s) # when i was young, i'd lis