Python copy & deeocopy 探究

发布时间 2023-06-27 13:12:49作者: BuckyI

简单来说,copy 复制创建新的容器,而引用容器内元素的地址不变。而 deepcopy 也对容器内的容器元素进行复制。
但是这种复制具体是什么体现呢?是否只是对第一层容器元素进行了复制?写了一段代码验证。

from collections.abc import Iterable
from pprint import pprint
from copy import deepcopy


def get_id(obj):
    if isinstance(obj, Iterable):
        return tuple((id(i), get_id(i)) for i in obj)
    else:
        return None


ls = [1, 1, [2, 22], [3, [3, 33]]]
ids = lambda obj: pprint((id(obj), get_id(obj)))

ids(ls)
ids(ls.copy())
ids(deepcopy(ls))
(139690047990528,
 ((139690060546288, None),
  (139690060546288, None),
  (139690050031936, ((139690060546320, None), (139690060546960, None))),
  (139690048039680,
   ((139690060546352, None),
    (139690048043392, ((139690060546352, None), (139690060547312, None)))))))

(139690048041088,
 ((139690060546288, None),
  (139690060546288, None),
  (139690050031936, ((139690060546320, None), (139690060546960, None))),
  (139690048039680,
   ((139690060546352, None),
    (139690048043392, ((139690060546352, None), (139690060547312, None)))))))

(139690048041088,
 ((139690060546288, None),
  (139690060546288, None),
  (139690048039808, ((139690060546320, None), (139690060546960, None))),
  (139690047983488,
   ((139690060546352, None),
    (139690050043008, ((139690060546352, None), (139690060547312, None)))))))

结论:

  • 数字类型元素的引用地址始终不变,同一个数字可被多次引用。
  • copy 只改变了最外层列表的地址,内部元素均相同。
  • deepcopy 改变了最外层以及内部所有列表(包括列表元素的列表元素)的地址。
  • ls.copy()deepcopy(ls) 的地址相同,猜测原因是程序中 ls.copy 返回的数据在打印结束后没有被使用了,便被销毁,同一个地址又用来存储 deepcopy(ls) 返回的结果。