pythoncopy函数_python-深度知识篇-copy(浅拷贝)deepcopy(深拷贝)

背景

开发工作中,有时候我们希望可以快速复制一个对象,python封装了内置函数copy模块中有copy与deepcopy函数,其中 copy是浅拷贝,deepcopy是深拷贝。在学习这俩个点时 我们需要弄清楚以下几点:为什么需要copy模块 ?

有了copy为什么需要deepcoy ,即与copy的差异?

如何自己实现一个copy方法?

如何自己实现一个deepcoy方法?

实例化的对象是可变对象还是不可变对象?

不论浅拷贝还是深拷贝,不可变对象内存地址与拷贝对象的内存地址一样,而可变对象内存地址与拷贝对象的内存地址不一样,这句话错在哪,举例说明?

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

通过阅读正文可以了解以上问题

预备知识1- 不可变对象与可变对象

不可变对象,不可以修改对象,使用id()方法获取对象的内存地址,a=b=2,id(a)与id(b)是一样的,当操作 a+=1时 a=3 ,而b=2,2这个对象是没有发生改变的,注意是对象而不是变量;不可变对对象的类型有,常见的有int,str,bool,float,None,tuple,bytes,frozenset。

可变对象,对象可以修改,此时内存地址不变,比如testone=[1,2],id(test_one)=140474965482144,testone.append(3),id(test_one)内存地址没发生变化,常见的可变对象有 list,dict,set,bytearray。

可变对象与不可变对象是非常基础与重要的概念,是一定需要理解的。

正文

我们可以想到,开发中可定会有需要使用到副本的时候,这时可以自己实现复制的方法,python中有很多对象,每一个开发者都去针对每一种对象实现一个复制函数,极大的增加了工作量,同时每一个开发者写法不一,没有统一。那可不可以封装一个函数,供开发者直接调用即可?

于是一个复制函数呼之欲出,则需求出现了。这个时候需要考虑不同对象类型的复制情况:

针对不可变对象,则定义复制函数为:

def copy_immutable(x):

return x

针对可变对象,不同对象类型的复制方法不一:

def copy_of_list(x):

y = []

for i in x:

y.append(i)

return y

def copy_of_set(x):

y = set()

for i in x:

y.add(i)

return y

def copy_of_dict(x):

y = {}

for k,v in x:

y[k]=v

return y

复制的方法定义好了,我们希望做进一步优化,包装一个函数,可以判断输入对象的类型,然后获取对应的复制方法,这样就可以有统一的接口了,代码如下:

# 定义不可变对象的类型清单,这里用的元组而非列表,这有什么好处了?

# 当前模块定义的全局使用的可变对象元组 相比使用列表或者集合有什么好处了?

# 元组有哪些好处了?

immutable_object_tuple = (type(None), int, float, bool, complex, str, tuple,bytes, frozenset)

# 定义复制解析字典,通过对象类型获取对应的复制方法

copy_dispatch =d={}

for t in immutable_object_tuple:

d[t]= copy_immutable

d[list]=copy_of_list

d[set]=copy_of_set

d[dict]=copy_of_dict

# 定义统一的复制函数,通过类型自动获取对应的复制方法

def copy_func_version_one(x):

cls = type(x) # 获取对象类型

copy_method = copy_dispatch[cls] # 假设解析方法已经包含了所有的类型,实际是没有了,后续再优化

return copy_method(x)

这个时候初步的复制函数出来了,可以类比为内建copy方法的雏形,在使用时可以满足基本的复制需求,但是如果可变对象嵌套可变对象了?用列表举例如下:

nest_one = [4, 5]

test_list_one = [1, 2, 3, nest_one]

copy_of_test_list_one = copy_of_list(test_list_one)

print(id(test_list_one))

print(id(copy_of_test_list_one))

# 139840569478192

# 139840540438032

# 可见复制后生成了 新的对象

print(id(copy_of_test_list_one[-1]))

print(id(test_list_one[-1]))

#139840569475632

#139840569475632

# 复制后的嵌套可变对象是同一个内存地址,是同一个对象,共用的test_one

总结:

我们发现内嵌的可变对象复制的时候没有生成的新的对象,还是以前的对象,当其中一个嵌套可变对象发生改变时,另外一个也会发生变化,复制时候感觉只复制了一层,我们叫这个为浅拷贝Shallow copy,那如何实现一个深拷贝了(deepcopy)? 下一节介绍

补充知识: 列表复制的多种方法

# python 内建模块copy

import copy

L1 = [1, 2, [3]]

L2 = L1

L3 = L1[:]

L4 = list(L1)

L5 = copy.copy(L1)

L6 = copy.deepcopy(L1)

if __name__ == '__main__':

print('L1 id is :{}'.format(id(L1)))

print('L1[2] id is :{}'.format(id(L1[2])))

print('L3 id is :{}'.format(id(L3)))

print('L3[2] id is :{}'.format(id(L3[2])))

print('L4 id is :{}'.format(id(L4)))

print('L4[2] id is :{}'.format(id(L4[2])))

print('L5 id is :{}'.format(id(L5)))

print('L5[2] id is :{}'.format(id(L5[2])))

print('L6 id is :{}'.format(id(L6)))

print('L6[2] id is :{}'.format(id(L6[2])))

# 输出

L1 id is :2148361819400

L1[2] id is :2148361819208

L3 id is :2148361820680

L3[2] id is :2148361819208

L4 id is :2148360362312

L4[2] id is :2148361819208

L5 id is :2148361820616

L5[2] id is :2148361819208

L6 id is :2148361820552

L6[2] id is :2148361820488

# 总结 可见几种复制方法中出了deepcopy,其他

# 都是浅复制,尤其注意list()方法的复制为浅复

#制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值