Python 直接赋值、浅拷贝和深度拷贝解析

概念说明

这里的直接赋值、浅拷贝和深度拷贝的对象都是列表或者是字典这样的复杂数据类型,像是整数或是字符串这样的基本数据类型不属于直接赋值等的范畴

  • 直接赋值: 为对象取别名
  • 浅拷贝(copy): 拷贝父对象,不会拷贝对象内部的子对象
  • 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

直接赋值

  • 如果是复杂数据类型变量(list,dict)的赋值操作视为为变量取别名,简单来说(以列表为例),列表a=[1,2,3] b = a,经过这样操作之后b实际上是数组a的别名,可以理解为b和a都是指向数组[1,2,3]的指针(python中没有指针操作),复制操作仅仅是将指针又重新复制了一份命名为b

    a = [1,2,3]
    # b是a的直接赋值
    b = a
    b.append(5)
    print("id(a):",id(a))
    print("id(b):",id(b))
    print("id(id(a))",id(id(a)))
    print("id(id(b))",id(id(b)))
    print("a",a)
    print("b",b)
    

    输出结果如下:

    id(a): 2656351178952
    id(b): 2656351178952
    id(id(a)) 2656384180144
    id(id(b)) 2656384180176
    a [1, 2, 3, 5]
    b [1, 2, 3, 5]
    

    id()用来取地址,上面的输出可以看出a和b代表的是同一块内存地址,并且当b修改时,a也随之修改

  • 如果是基本数据类型的变量赋值是创建一个新的副本

    a = "string"
    b = a
    b += "78"
    print("a:",a)
    print("b:",b)
    print(id(a))
    print(id(b))
    

    结果如下:

    a: string
    b: string78
    2840820288456
    2840827133872
    

    可以看到a和b是在不同的内存中,b的修改不会影响a的值

浅拷贝

a = [1,[1,2,3]]
# b是a的浅拷贝
b = a.copy()
print("id(a):",id(a))
print("id(b):",id(b))
b[0]=4
print("a:",a)
print("b:",b)
print("id(a[1])", id(a[1]))
print("id(b[1])", id(b[1]))
b[1].append(5)
print("a:", a)
print("b:", b)

输出:

id(a): 1493887745032
id(b): 1493887822536
# a和b的地址不同,说明a和b有属于各自的内存分配
a: [1, [1, 2, 3]]
b: [4, [1, 2, 3]]
# 修改b中的简单数据类型对象,a不变
id(a[0]) 1992059968
id(b[0]) 1992060064
# b和a中的基本数据类型对象地址不同,二者独立存在
id(a[1]) 1493846348168
id(b[1]) 1493846348168
# b和a中的复杂数据类型对象的地址相同说明二者的复杂数据类型是指向了同一片空间
a: [1, [1, 2, 3, 5]]
b: [4, [1, 2, 3, 5]]
# 修改后得到佐证

上面的例子说明,复杂数据类型的浅拷贝完全复制了内存中的简单数据类型,对于复杂的数据类型使用的是储存了一个别名,具体如下:

#浅拷贝操作等价于这样
a = [1,[1,2,3]]
a0=a[0]
a1=a[1]
b = []
b.append(a0)
b.append(a1)

如果是使用上面的输出可得到相同的结果

id(a): 2476418727368
id(b): 2476395376072
a: [1, [1, 2, 3]]
b: [4, [1, 2, 3]]
id(a[0]) 1992059968
id(b[0]) 1992060064
id(a[1]) 2476368929544
id(b[1]) 2476368929544
a: [1, [1, 2, 3, 5]]
b: [4, [1, 2, 3, 5]]

深度拷贝

深度拷贝使用copy模块的deepcoy方法,将数据完全复制一份放到另一块内存中,不论是否复杂数据类型变量中含有列表或字典

from copy import deepcopy
a = [1,[1,2,3]]
b = deepcopy(a)
print("id(a):",id(a))
print("id(b):",id(b))
b[0]=4
print("a:",a)
print("b:",b)
print("id(a[0])", id(a[0]))
print("id(b[0])", id(b[0]))
print("id(a[1])", id(a[1]))
print("id(b[1])", id(b[1]))
b[1].append(5)
print("a:", a)
print("b:", b)
'''
	b = deepcopy(a)
	等价于
	b = []
	a0 = a[0]
	a1 = deepcopy(a[1])
	b.append(a0)
	b.append(a1)
'''

输出如下:

id(a): 1613491154632
id(b): 1613491213576
a: [1, [1, 2, 3]]
b: [4, [1, 2, 3]]
id(a[0]) 1992059968
id(b[0]) 1992060064
id(a[1]) 1613475312712
id(b[1]) 1613446907144
# a[1]和b[1]的地址不同指向不同的内存
a: [1, [1, 2, 3]]
b: [4, [1, 2, 3, 5]]

上面三部分参考自:(菜鸟教程)Python 直接赋值、浅拷贝和深度拷贝解析

Python中读取指定内存地址的值

  • 在C/C++中我们有&取地址操作,使用*进行输出地址的值操作
  • 在python中我们使用id()函数进行取地址操作,但是没有内置函数用来输出地址的值,在这里使用ctypes模块实现类似的功能
import ctypes
values='hello world' 	#定义一个字符串字面量
address=id(value)		#获取value地址,赋值给address
print(address)
get_value = ctypes.cast(address,ctypes.py_object).value #读取地址中的变量
print(get_value)

输出

2026299085168
hello world

以上部分来自链接:Python通过地址获取变量

ctypes模块

ctypes模块是用来在python中使用C数据类型的模块

NAME
    ctypes - create and manipulate C data types in Python

在ctypes模块中的cast函数说明(貌似有些草率)

    cast(obj, typ)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是兔不是秃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值