今天突然有兴趣研究一下python的深拷贝:
因为有循环调用 ,我在文中都是用1,2,3这样标明怎么跳代码的,可能要读者多翻一下,没有几页。
deepcopy()为入口函数:
Import copy
if __name__ == '__main__':
# main(sys.argv)
list1 = [1,2,3]
# a = runManualTask()
b = copy.deepcopy(list1) // 从这里入口
从以下代码的 ->1 开始
def deepcopy(x, memo=None, _nil=[]): // (->9, _deepcopy_list() 函数中会三次调用到这个函数->跳到10处
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {}
d = id(x)
y = memo.get(d, _nil)
if y is not _nil:
return y
cls = type(x) // (->1.这里就是获取被copy的是什么类型的,这里我们是用的list, 所以cls值为:list
copier = _deepcopy_dispatch.get(cls) // (->2.这里就是用list 为key找到用哪个函数来copy,那如何找到的呢? 跳到3处继续看:
if copier: // (->6. 这里就是_deepcopy_list
y = copier(x, memo) // (->7. 调用_deepcopy_list()-> 跳到8看一下这个函数是怎么用的:
else:
try:
issc = issubclass(cls, type)
except TypeError: # cls is not a class (old Boost; see SF #502085)
issc = 0
if issc:
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)
if copier:
y = copier(memo)
else:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()
else:
raise Error(
"un(deep)copyable object of type %s" % cls)
if isinstance(rv, str):
y = x
else:
y = _reconstruct(x, memo, *rv)
# If is its own copy, don't memoize.
if y is not x:
memo[d] = y
_keep_alive(x, memo) # Make sure x lives at least as long as d
return y // (->10. deepcopy_list 每次调用这个函数的时候,会从这里返回list中单个元素的值->跳回到deepcopy_list函数中的11
以下代码是->3
copier = _deepcopy_dispatch.get(cls) // -> 3 从这里看这个_deepcopy_dispath是个什么东东
进到_deepcopy_dispatch 中发现
_deepcopy_dispatch = d = {}
第其实是指向d 的,那d里是什么呢?
从下边的代码可以看到,就是指什么样的类型用什么样的函数来copy:
def _deepcopy_atomic(x, memo):
return x
d[type(None)] = _deepcopy_atomic // ->4 可以看到d[]中其实就是保存了所有的函数指针
d[type(Ellipsis)] = _deepcopy_atomic
d[type(NotImplemented)] = _deepcopy_atomic
d[int] = _deepcopy_atomic
d[float] = _deepcopy_atomic
d[bool] = _deepcopy_atomic
d[complex] = _deepcopy_atomic
d[bytes] = _deepcopy_atomic
d[str] = _deepcopy_atomic
try:
d[types.CodeType] = _deepcopy_atomic
except AttributeError:
pass
d[type] = _deepcopy_atomic
d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic
d[weakref.ref] = _deepcopy_atomic
def _deepcopy_list(x, memo, deepcopy=deepcopy):
y = []
memo[id(x)] = y
append = y.append
for a in x:
append(deepcopy(a, memo))
return y
d[list] = _deepcopy_list ( ->5. 那list应该是用这个函数指针来copy 数据的
这里知道是用_deepcopy_list 这个函数来copy了。那回到2的地方。我把上边的代码copy到下边来看:
下边的 ->2 之后就是 6,7 步骤了
def deepcopy(x, memo=None, _nil=[]): // (->9, _deepcopy_list() 函数中会三次调用到这个函数->跳到10处
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {}
d = id(x)
y = memo.get(d, _nil)
if y is not _nil:
return y
cls = type(x) // (->1.这里就是获取被copy的是什么类型的,这里我们是用的list, 所以cls值为:list
copier = _deepcopy_dispatch.get(cls) // (->2.这里就是用list 为key找到用哪个函数来copy,那如何找到的呢? 跳到3处继续看:
if copier: // (->6. 这里就是_deepcopy_list
y = copier(x, memo) // (->7. 调用_deepcopy_list()-> 跳到8看一下这个函数是怎么用的:
else:
try:
issc = issubclass(cls, type)
except TypeError: # cls is not a class (old Boost; see SF #502085)
issc = 0
if issc:
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)
if copier:
y = copier(memo)
else:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()
else:
raise Error(
"un(deep)copyable object of type %s" % cls)
if isinstance(rv, str):
y = x
else:
y = _reconstruct(x, memo, *rv)
# If is its own copy, don't memoize.
if y is not x:
memo[d] = y
_keep_alive(x, memo) # Make sure x lives at least as long as d
return y // ->10. deepcopy_list()函数里每次调用这个函数的时候,会从这里返回list中单个元素的值, 1 或2,或3; 当deepcopy_list() 已经完全执行完成后,这里返回的是 [1,2,3]
->8. 那我们来看一下 ->7 是怎么调用的 _deepcopy_list()
. def _deepcopy_list(x, memo, deepcopy=deepcopy):
y = []
memo[id(x)] = y
append = y.append
for a in x: // 这里x 中list有3个元素[1,2,3],那就会分别调用3次deepcopy() 函数-> 跳到9处
append(deepcopy(a, memo)) // 这里再次调用 deepcopy()时,转入的参数就是1,或者2, 或者3.然后每次返回的是一个整数。最终保存到y中。
return y // (->11, 3次调用deepcopy后,这里就已经复制好了。把Y返回回去。
d[list] = _deepcopy_list
上边的 _deepcopy_list()返回就是回到下图的Deepcopy()函数的7 处
Deepcopy()函数的7 处。然后跳过else{}->执行 10处的return y. 这样list 深copy完成。
def deepcopy(x, memo=None, _nil=[]): // (->9, _deepcopy_list() 函数中会三次调用到这个函数->跳到10处
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {}
d = id(x)
y = memo.get(d, _nil)
if y is not _nil:
return y
cls = type(x) // (->1.这里就是获取被copy的是什么类型的,这里我们是用的list, 所以cls值为:list
copier = _deepcopy_dispatch.get(cls) // (->2.这里就是用list 为key找到用哪个函数来copy,那如何找到的呢? 跳到3处继续看:
if copier: // (->6. 这里就是_deepcopy_list
y = copier(x, memo) // (->7. 调用_deepcopy_list()
else:
try:
issc = issubclass(cls, type)
except TypeError: # cls is not a class (old Boost; see SF #502085)
issc = 0
if issc:
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)
if copier:
y = copier(memo)
else:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()
else:
raise Error(
"un(deep)copyable object of type %s" % cls)
if isinstance(rv, str):
y = x
else:
y = _reconstruct(x, memo, *rv)
# If is its own copy, don't memoize.
if y is not x:
memo[d] = y
_keep_alive(x, memo) # Make sure x lives at least as long as d
return y // 10 当调用最终完成进,这里返回的是一个新的数组,存的[1,2,3]
总结:
深拷贝时,其实用到的嵌套调用。 在调用哪个函数时,用对象的类型来从dict中找用哪个函数,然后递归直到找到基本类型。最后返回新分配的空间给目标对象。