python中的深拷贝和浅拷贝(详解)

目录

一:可变对象,与 不可变对象分别是什么,什么意思?

1、什么是可变对象,有哪些?

2、什么是不可变对象,有哪些?

二:为什么要用不可变对象?

三:数据类型转换

四:深拷贝、浅拷贝 分别是什么,怎么使用?

1、拷贝、赋值是什么意思?

2、对于不可变对象(数字、字符串)拷贝会不会申请新的内存?

五:浅拷贝详解:

六:深拷贝详解:

七:总结


一:可变对象,与 不可变对象分别是什么,什么意思?

1、什么是可变对象,有哪些?

除ID之外,其他状态都有可能发生改变
可变对象有:列表、集合、字典
l = []
print("修改前id= ", id(l))

l.append(132)
print("修改后id= ", id(l))
print(l)

结果:
修改前id=  2597667097216
修改后id=  2597667097216
[132]

2、什么是不可变对象,有哪些?

包括id在内的各种状态,都不会发生变化

不可变对象有:大部分是python内置数据类型: 数字,字符串,元组

i = 123
print("修改前id= ", id(i))

i = 456
print("修改后id= ", id(i))  # id 变化了,说明数据的修改不是建立在原内存的, 而是新申请了内存,保存新的值
print(i)

结果:
修改前id=  2597665527984
修改后id=  2597669816432
456

实例:

a = 100
b = a

# 关于a

print("数据类型: ", type(a))
print("唯一表示: ", id(a))
print("数据成员: ", dir(a))
print("是否调用: ", callable(a.from_bytes))  # 可能是方法(需要调用),也可能是属性(不需要调用)
print("方法的用法:", help(a.from_bytes))  # 可能是方法(需要调用),也可能是属性(不需要调用)

print("-" * 150)

# 关于b
print("数据类型: ", type(b))
print("唯一表示: ", id(b))
print("数据成员: ", dir(b))
print("是否调用: ", callable(b.from_bytes))  # 可能是方法(需要调用),也可能是属性(不需要调用)
print("方法的用法:", help(b.from_bytes))  # 可能是方法(需要调用),也可能是属性(不需要调用)

print("-" * 200)
if id(a) == id(b):
    print("a 和 b 是同一个对象")
print("-" * 150)
if a is b:
    print("a 和 b 是同一个对象")  # 内存地址 , 是相同的
print("-" * 150)
if a == b:
    print("a 和 b 的值 是相等的")  # 内存地址中的值 , 是相同的
运行结果:
数据类型:  <class 'int'>
唯一表示:  2597665527248
数据成员:  ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
是否调用:  True
Help on built-in function from_bytes:

from_bytes(bytes, byteorder, *, signed=False) method of builtins.type instance
    Return the integer represented by the given array of bytes.
    
    bytes
      Holds the array of bytes to convert.  The argument must either
      support the buffer protocol or be an iterable object producing bytes.
      Bytes and bytearray are examples of built-in objects that support the
      buffer protocol.
    byteorder
      The byte order used to represent the integer.  If byteorder is 'big',
      the most significant byte is at the beginning of the byte array.  If
      byteorder is 'little', the most significant byte is at the end of the
      byte array.  To request the native byte order of the host system, use
      `sys.byteorder' as the byte order value.
    signed
      Indicates whether two's complement is used to represent the integer.

方法的用法: None
------------------------------------------------------------------------------------------------------------------------------------------------------
数据类型:  <class 'int'>
唯一表示:  2597665527248
数据成员:  ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
是否调用:  True
Help on built-in function from_bytes:

from_bytes(bytes, byteorder, *, signed=False) method of builtins.type instance
    Return the integer represented by the given array of bytes.
    
    bytes
      Holds the array of bytes to convert.  The argument must either
      support the buffer protocol or be an iterable object producing bytes.
      Bytes and bytearray are examples of built-in objects that support the
      buffer protocol.
    byteorder
      The byte order used to represent the integer.  If byteorder is 'big',
      the most significant byte is at the beginning of the byte array.  If
      byteorder is 'little', the most significant byte is at the end of the
      byte array.  To request the native byte order of the host system, use
      `sys.byteorder' as the byte order value.
    signed
      Indicates whether two's complement is used to represent the integer.

方法的用法: None
 特殊情况: 虽然也会创建新的对象,但是原对象没有发生变化
 对于可变对象来说,也不一定每一次的修改都是在 原内存空间进行的



二:为什么要用不可变对象?

函数式编程对象: 函数第一、***不可变数据***、尾递归、柯里化
字典的 key 必须是不可变的,可哈希的,字典是个mapping 必须保持不变
复用 相同的数据,可以提高效率
l = [1, 2, 3]
_id = id(l)
d = {}
d[id(l)] = "cjw"
l.append(4)
print(d[id(l)])
print(l)

运行结果:
cjw
[1, 2, 3, 4]



三:数据类型转换

Python 中的数据类型,一定不是原内存进行修改
实际上是创建新的对象,这意味使用新的 内存地址
print("*"* 200)
a = "1111"
l = list(a)
ll = tuple(a)
lll = set(a)
llll = str(a)   # 新的字符串,字符串属于不可变对象 0-1000数字整数复用空间
print(type(a),id(a))
print(type(l),id(l))
print(type(ll),id(ll))
print(type(lll),id(lll))
print(type(llll),id(llll))


运行结果:
<class 'str'> 2597670120240
<class 'list'> 2597667032896
<class 'tuple'> 2597670251952
<class 'set'> 2597673348448
<class 'str'> 2597670120240


四:深拷贝、浅拷贝 分别是什么,怎么使用?

1、拷贝、赋值是什么意思?

=:  是指赋值,讲符号左右的变量名指向数据
拷贝: 复制了一份一样的数据,需要申请新的内存

通过copy模块来实现,有 2 种:

        浅拷贝

        深拷贝

l = []
ll = l
print("l id",id(l))
print("ll id",id(ll))

运行结果:
l id 2133639698368
ll id 2133639698368

l = []
ll = l 是赋值  ,指ll 指向 l 的内存地址
赋值 不会创建对象,不会去申请内存地址  

2、对于不可变对象(数字、字符串)拷贝会不会申请新的内存?

不会,重复使用内存中的数字、字符串,不可以拷贝

五:浅拷贝详解:

浅拷贝做两件事:
1、为*目标对象*创建副本
2、将*副本对象*的成员,指向“目标对象”的成员
只为对象开辟了内存,没有对 对象的成员开辟了内存
 浅拷贝的意义:
        为浅拷贝的对象创建了新内存地址,没有对对象成员开辟新的内存地址,增强了复用性;

copy.copy()

d = {
    "l":[],
    "ll":123
}
l = copy.copy(d)  # 没有创建数据 , l 是新的内存地址
# l 是新的字典,拥有和d一样的成员
print(id(l),type(l))
print(id(d),type(d))

运行结果:
2441833583232 <class 'dict'>
2441836525312 <class 'dict'>

浅拷贝考虑两种情况:

一:对原对象做出了修改

        可变对象的修改:1.内容变了,2.ID没变

        副本对象,跟着发生变化

二: 对原对象没有做出修改------------> 没有对目标对象进行修改,只是成员指向另一个内存

        没有修改,1、内容变了,2、ID变了

        副本对象,没有发生变化

六:深拷贝详解:

深拷贝做了三件事:
为“目标对象”创建副本(开辟内存)
为目标对象的成员“创建副本”,以及成员的对象(开辟内存)
将“副本对象”的成员,指向新创建的副本成员

copy.deepcopy()

七:总结

浅拷贝:为对象开辟新内存,没有对 对象成员开辟内存

深拷贝:   为对象开辟新内存,也对对象成员开辟内存

什么情况下用到:
        深拷贝:
        完整的复制一份数据,以期望原数据的修改,不会对副本产生影响
        该有的全部 备份了,弊端:成本比较高

        浅拷贝:
        只复制目标,而不复制目标的成员,低沉本完成目标的复制
        只是复制了一个空壳

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深拷贝(deep copy)和浅拷贝(shallow copy)是Python关于对象复制的两个概念。 浅拷贝是指创建一个新的对象,其内容是原始对象的引用。也就是说,新对象与原始对象共享内存地址,对其一个对象的修改会影响到另一个对象。在Python,可以使用`copy`模块的`copy()`函数或者对象的`copy()`方法进行浅拷贝深拷贝则是创建一个新的对象,完全复制原始对象及其所有嵌套对象的内容。也就是说,新对象与原始对象完全独立,互不影响。在Python,可以使用`copy`模块的`deepcopy()`函数或者对象的`deepcopy()`方法进行深拷贝。 下面是一个简单的示例代码来说明深拷贝浅拷贝的区别: ```python import copy # 原始对象 original_list = [1, 2, [3, 4]] print("原始对象:", original_list) # 浅拷贝 shallow_copy_list = copy.copy(original_list) print("浅拷贝对象:", shallow_copy_list) # 修改浅拷贝对象 shallow_copy_list[2][0] = 5 print("修改浅拷贝对象后,原始对象:", original_list) print("修改浅拷贝对象后,浅拷贝对象:", shallow_copy_list) # 深拷贝 deep_copy_list = copy.deepcopy(original_list) print("深拷贝对象:", deep_copy_list) # 修改深拷贝对象 deep_copy_list[2][1] = 6 print("修改深拷贝对象后,原始对象:", original_list) print("修改深拷贝对象后,深拷贝对象:", deep_copy_list) ``` 输出结果为: ``` 原始对象: [1, 2, [3, 4]] 浅拷贝对象: [1, 2, [3, 4]] 修改浅拷贝对象后,原始对象: [1, 2, [5, 4]] 修改浅拷贝对象后,浅拷贝对象: [1, 2, [5, 4]] 深拷贝对象: [1, 2, [3, 4]] 修改深拷贝对象后,原始对象: [1, 2, [5, 4]] 修改深拷贝对象后,深拷贝对象: [1, 2, [3, 6]] ``` 可以看到,对浅拷贝对象的修改会影响到原始对象,而对深拷贝对象的修改不会影响原始对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值