28

python standard library copy

 4 years ago
source link: https://pinghailinfeng.gitee.io/2020/02/02/python-standard-library-copy/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

RNbUvmY.png!web

源码

源代码: Lib/copy.py

类层次结构

Interface summary:
        import copy
        x = copy.copy(y)        # make a shallow copy of y
        x = copy.deepcopy(y)    # make a deep copy of y

Python 中赋值语句不复制对象,而是在目标和对象之间创建绑定 (bindings) 关系。对于自身可变或者包含可变项的集合对象,开发者有时会需要生成其副本用于改变操作,进而避免改变原对象。本模块提供了通用的浅层复制和深层复制操作(如下所述)。

接口摘要:

  • copy.copy ( x )

    返回 x 的浅层复制。

  • copy.deepcopy ( x [, memo ])

    返回 x 的深层复制。

  • exception copy.error

    针对模块特定错误引发。

浅层复制和深层复制之间的区别仅与复合对象 (即包含其他对象的对象,如列表或类的实例) 相关:

  • 一个 浅层复制 会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用 插入其中。
  • 一个 深层复制 会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本 插入。

深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题:

  • 递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。
  • 由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)。

The deepcopy() function avoids these problems by:

memo

该模块不复制模块、方法、栈追踪(stack trace)、栈帧(stack frame)、文件、套接字、窗口、数组以及任何类似的类型。它通过不改变地返回原始对象来(浅层或深层地)“复制”函数和类;这与 pickle 模块处理这类问题的方式是相似的。

制作字典的浅层复制可以使用 dict.copy() 方法,而制作列表的浅层复制可以通过赋值整个列表的切片完成,例如, copied_list = original_list[:]

类可以使用与控制序列化(pickling)操作相同的接口来控制复制操作,关于这些方法的描述信息请参考 pickle 模块。实际上, copy 模块使用的正是从 copyreg 模块中注册的 pickle 函数。

想要给一个类定义它自己的拷贝操作实现,可以通过定义特殊方法 __copy__()__deepcopy__() 。 调用前者以实现浅层拷贝操作,该方法不用传入额外参数。 调用后者以实现深层拷贝操作;它应传入一个参数即 memo 字典。 如果 __deepcopy__() 实现需要创建一个组件的深层拷贝,它应当调用 deepcopy() 函数并以该组件作为第一个参数,而将 memo 字典作为第二个参数。

实例

字典拷贝

import copy
 
 
def displayList(text, dictOfElements) :
    print("--------")
    print(text)
    for key , value in dictOfElements.items():
        print(key, " :: ", value)
 
def main():
    
    # Dictionary of strings and ints
    wordsDict = {
        "Hello": 56,
        "at" : 23 ,
        "test" : 43,
        "this" : 43,
        "who" : [56, 34, 44]
        }
    
    '''
    Shallow Copying dictionaries using dict.copy()
    '''
    print("***** Shallow Copy *********")
    
    displayList("Original Dictionary : " , wordsDict)
    
    # create a Shallow copy  the original dictionary
    newDict = wordsDict.copy()
    
    # Modify the value of key in new dictionary
    newDict["at"] = 200
    
    print("Contents of copied dictionary changed")
 
    displayList("Modified copied dictionary : " , newDict)
    
    displayList("Original Dictionary : " , wordsDict)
 
    '''
    Modify the contents of list object in shallow copied dictionary will 
    modify the contents of original dictionary too because its a shallow copy. 
    '''
    newDict["who"].append(222)
    
    print("Contents of list in copied dictionary changed")
 
    displayList("Modified copied dictionary : " , newDict)
    
    displayList("Original Dictionary : " , wordsDict)
 
    print("***** Deep Copy *******")
    
    displayList("Original Dictionary : " , wordsDict)
    
    # Create a deep copy of the dictionary
    otherDict = copy.deepcopy(wordsDict)
    
    displayList("Deep copy of  Dictionary : " , otherDict)
    
    '''
    Modify the contents of list object in deep copied dictionary will 
    have no impact on original dictionary because its a deep copy.
    '''
    newDict["who"].append(100)
 
    displayList("Modified Deep copy of Dictionary : " , otherDict)
    displayList("Original Dictionary : " , wordsDict)
    
if __name__ == '__main__':
    main()

结果

--------
Original Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44]
Contents of copied dictionary changed
--------
Modified copied dictionary : 
at  ::  200
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44]
--------
Original Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44]
Contents of list in copied dictionary changed
--------
Modified copied dictionary : 
at  ::  200
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222]
--------
Original Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222]
***** Deep Copy *******
--------
Original Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222]
--------
Deep copy of  Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222]
--------
Modified Deep copy of Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222]
--------
Original Dictionary : 
at  ::  23
this  ::  43
Hello  ::  56
test  ::  43
who  ::  [56, 34, 44, 222, 100]

列表拷贝

浅拷贝

使用 = 赋值运算符

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 'a']]
new_list = old_list

new_list[2][2] = 9

print('Old List:', old_list)
print('ID of Old List:', id(old_list))

print('New List:', new_list)
print('ID of New List:', id(new_list))

使用 copy 浅拷贝

import copy

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
new_list = copy.copy(old_list)

print("Old list:", old_list)
print("New list:", new_list)

使用 deepcopy 深拷贝

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.deepcopy(old_list)

print("Old list:", old_list)
print("New list:", new_list)

类拷贝

import copy

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f'Point({self.x!r}, {self.y!r})'
    
>>> a = Point(23, 42)
>>> b = copy.copy(a)
>>> a
Point(23, 42)
>>> b
Point(23, 42)
>>> a is b
False

## 使用copy模块的copy方法
class Rectangle:
    def __init__(self, topleft, bottomright):
        self.topleft = topleft
        self.bottomright = bottomright

    def __repr__(self):
        return (f'Rectangle({self.topleft!r}, '
                f'{self.bottomright!r})')
rect = Rectangle(Point(0, 1), Point(5, 6))
srect = copy.copy(rect)

>>> rect
Rectangle(Point(0, 1), Point(5, 6))
>>> srect
Rectangle(Point(0, 1), Point(5, 6))
>>> rect is srect
False
>>> rect.topleft.x = 999
>>> rect
Rectangle(Point(999, 1), Point(5, 6))
>>> srect
Rectangle(Point(999, 1), Point(5, 6))
>>> drect = copy.deepcopy(srect)
>>> drect.topleft.x = 222
>>> drect
Rectangle(Point(222, 1), Point(5, 6))
>>> rect
Rectangle(Point(999, 1), Point(5, 6))
>>> srect
Rectangle(Point(999, 1), Point(5, 6))
    
## 使用copy方法
class Rectangle(object):
    def __init__(self, topleft, bottomright):
        self.topleft = topleft
        self.bottomright = bottomright

    def __repr__(self):
        return (f'Rectangle({self.topleft!r}, '
                f'{self.bottomright!r})')
    def copy(self):
        return Rectangle(self.topleft, self.bottomright)



r1  = Rectangle(20,30)
r2  =r1.copy()
print("r1:",r1)
print("r2:",r2)

>>> r1: Rectangle(20, 30)
>>> r2: Rectangle(20, 30)

一个深入的例子

class B(object):
    x = 3

CopyOfB = type('CopyOfB', B.__bases__, dict(B.__dict__))

b = B()
cob = CopyOfB()

print b.x   # Prints '3'
print cob.x # Prints '3'

b.x = 2
cob.x = 4

print b.x   # Prints '2'
print cob.x # Prints '4'

class C(object):
    x = []

CopyOfC = type('CopyOfC', C.__bases__, dict(C.__dict__))

c = C()
coc = CopyOfC()

c.x.append(1)
coc.x.append(2)

print c.x   # Prints '[1, 2]' (!)
print coc.x # Prints '[1, 2]' (!)

参考文档

how to deep copy a list

shallow-deep-copy

how-to-copy-a-python-class

最后

最近学到一个新词: 共克时艰 翻译成 英文 We are suffering ,希望和朋友们共勉。

我们都是蝴蝶翅膀上的那粒灰尘,被裹挟在龙卷风里,谁都晕头转向


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK