首页 > 代码库 > Shallow copy and Deep copy

Shallow copy and Deep copy

一、来自wikipidia的解释:

Shallow copy

One method of copying an object is the shallow copy. In that case a new object B is created, and the fields values of A are copied over to B. This is also known as a field-by-field copy,field-for-field copy, or field copy. If the field value is a reference to an object (e.g., a memory address) it copies the reference, hence referring to the same object as A does, and if the field value is a primitive type it copies the value of the primitive type. In languages without primitive types (where everything is an object), all fields of the copy B are references to the same objects as the fields of original A. The referenced objects are thus shared, so if one of these objects is modified (from A or B), the change is visible in the other. Shallow copies are simple and typically cheap, as they can be usually implemented by simply copying the bits exactly.

复制对象的一种方法是浅拷贝。 在这种情况下,将创建一个新对象B,并将A的字段值复制到B.这也称为逐字段复制,或字段复制。 如果字段值是对对象(例如,存储器地址)的引用,则它复制引用,因此引用与A相同的对象,并且如果字段值是原始类型,则它复制原始类型的值。 在没有原始类型的语言(其中一切都是对象)中,副本B的所有字段都引用与原始A的字段相同的对象。因此,共享引用的对象,因此如果这些对象中的一个被修改(从A 或B),变化在另一个中可见。 浅拷贝很简单,通常很便宜,因为它们通常可以通过简单地复制这些位来实现。

Deep copy

An alternative is a deep copy, meaning that fields are dereferenced: rather than references to objects being copied, new copy objects are created for any referenced objects, and references to these placed in B. The result is different from the result a shallow copy gives in that the objects referenced by the copy B are distinct from those referenced by A, and independent. Deep copies are more expensive, due to needing to create additional objects, and can be substantially more complicated, due to references possibly forming a complicated graph.

另一种方法是深拷贝,意思是字段被解引用:而不是对被拷贝的对象的引用,为任何引用的对象创建新的拷贝对象,并且将这些对象的引用放置在B.结果不同于浅拷贝给出的结果 因为副本B引用的对象与A引用的对象不同,并且是独立的。 由于需要创建附加对象,深拷贝更加昂贵,并且由于可能形成复杂图形的引用,可能显着更复杂。

 技术分享技术分享

In Python, the library‘s copy module provides shallow copy and deep copy of objects through the copy() and deepcopy() functions, respectively.Programmers may define special methods __copy__() and __deepcopy__() in an object to provide custom copying implementation.

In VBA, an assignment of variables of type Object is a shallow copy, an assignment for all other types (numeric types, String, user defined types, arrays) is a deep copy. So the keyword Set for an assignment signals a shallow copy and the (optional) keyword Let signals a deep copy. There is no built-in method for deep copies of Objects in VBA.

 

二、来自Python的List实例

在Python中,引用是指从变量到对象的连接,即保存的值为对象的地址,它是一种关系,以内存中的指针形式实现。

在Python中,一个变量保存的值除了基本类型保存的是值外,其它都是引用。

变量:是一个系统表的元素,拥有指向对象连接的空间。

对象:是被分配的一块内存,有足够的空间去表现它们所代表的值。

引用:自动形成的从变量到对象的指针。

共享引用:

>>> L1 = [1, 2, 3]
>>> L2 = L1
>>> L1.append(4)
>>> L2
>>> [1, 2, 3, 4]
L1与L2指向内存中的同一对象,对其中一个对象的修改都会影响另一个对象的值,即L1与L2共享引用对象。

解决方法:

>>> L1 = [1, 2, 3]
>>> L2 = L1.copy() # list.copy()-->
Return a shallow copy of the list. Equivalent to a[:].
>>> L1.append(4)
>>> L1
>>> [1, 2, 3, 4]
>>> L2
>>> [1, 2, 3]

以上例子只适用于简单列表,也就是列表中的元素都是基本类型,如果列表元素还存在列表的话,这种方法就不适用了。原因就是,象a.copy()这种处理方法,只是将列表元素的值生成一个新的列表,如果列表元素也是一个列表,如:a=[1,2,3,4,[‘a‘,‘b‘]],那么这种复制对于元素[‘a‘,‘b‘]的处理只是复制[‘a‘,‘b‘]的引用,而并未生成 [‘a‘,‘b‘]的一个新的列表复制。代码如下:

>>> a = [1, 2, 3, 4, [a, b]]
>>> b = a.copy()
>>> a[4].append(c)
>>> b
>>> [1, 2, 3, 4, [a, b, c]]

解决方法:copy模块,请参考第三节。

 

 三、来自Python的模块copy

copy — Shallow and deep copy operations

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other. This module provides generic shallow and deep copy operations (explained below).

Interface summary:

copy.copy(x)  -->Return a shallow copy of x.
Shallow copy operation on arbitrary Python objects.
See the module‘s __doc__ string for more info.
copy.deepcopy(x)  -->Return a deep copy of x.

deepcopy(x, memo=None, _nil=[])

Deep copy operation on arbitrary Python objects.

See the module‘s __doc__ string for more info.

exception copy.error  -->Raised for module specific errors.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

Two problems often exist with deep copy operations that don’t exist with shallow copy operations:

  • Recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) may cause a recursive loop.
  • Because deep copy copies everything it may copy too much, e.g., administrative data structures that should be shared even between copies.

The deepcopy() function avoids these problems by:

  • keeping a “memo” dictionary of objects already copied during the current copying pass; and
  • letting user-defined classes override the copying operation or the set of components copied.

This module does not copy types like module, method, stack trace, stack frame, file, socket, window, array, or any similar types. It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.

Shallow copies of dictionaries can be made using dict.copy(), and of lists by assigning a slice of the entire list, for example, copied_list = original_list[:].

Classes can use the same interfaces to control copying that they use to control pickling. See the description of module pickle for information on these methods. In fact, the copy module uses the registered pickle functions from the copyreg module.

In order for a class to define its own copy implementation, it can define special methods __copy__() and __deepcopy__(). The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary. If the __deepcopy__() implementation needs to make a deep copy of a component, it should call the deepcopy() function with the component as first argument and the memo dictionary as second argument.

 

See also

Module pickle
Discussion of the special methods used to support object state retrieval and restoration. 

实例:

>>> import copy
>>> a = [1, 2, 3, 4, [a, b]]
>>> b = a 
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append(c)

>>> a
>>> [1, 2, 3, 4, [‘a‘, ‘b‘, ‘c‘], 5]
>>> b >>> [1, 2, 3, 4, [a, b,c], 5] >>> c >>> [1, 2, 3, 4, [a, b,c]] >>> d >>> [1, 2, 3, 4, [a, b]]

 

 

 

 

参考文章:

[1] --> https://en.wikipedia.org/wiki/Object_copying#Shallow_copy

[2] --> http://www.jb51.net/article/64030.htm

[3] --> http://www.jb51.net/article/15714.htm

[4] --> https://docs.python.org/3/library/copy.html

[5] --> Learning Python 3rd Edition

 

Shallow copy and Deep copy