赋值
在 python 中,赋值是将一个值或对象分配给一个变量的过程。赋值操作符是 =
,用于将右侧的值或对象赋给左侧的变量。
赋值:l2的值会随着原对象l1的值一同改变
l1 = [1, 2, 3, 4]
print('l1:', l1)
l2 = l1
print('l2:', l2)
给li列表新增元素
l1.append(5)
print('l1', l1)
print('l2', l2)
输出后可以看到l1和l2两个列表同时增加了5
赋值等于完全共享资源,一个值的改变会完全被另一个值共享
深浅拷贝:
在 Python 中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是用来复制对象的两种方式,它们的主要区别在于如何处理对象内部的嵌套结构(如列表、字典、对象等)。
浅拷贝
创建一个新对象,但不递归地复制嵌套对象。换句话说,它创建了一个新的容器对象,并插入了对原始对象中元素的引用。如果嵌套对象(如列表中的列表)被修改,原始对象中的内容也会受到影响。浅拷贝的数据半共享。浅拷贝会创建一个新的对象,拷贝第一层的数据,嵌套层会指向原来的内存地址
import copy # 导入copy模块
l1 = [1, 2, 3, [4, 5, 6]] # 定义一个嵌套列表
l2 = copy.copy(l1)
print('l2', l2)
查看内存地址
print('l1的内存地址:', id(l1))
print('l2的内存地址:', id(l2))
内存地址不一样,说明不是同一个对象
往列表增加元素
l1.append(8)
print('l1', l1)
print('l2', l2)
# 往嵌套列表增加元素
l1[3].append(7)
print('l1', l1)
print('l2', l2)
print('l1[3]的内存地址:', id(l1[3]))
print('l2[3]的内存地址:', id(l2[3]))
外层的内存地址不同,但是内层的内存地址相同
优点:拷贝速度快,占用空间少,拷贝效率高
深拷贝
创建一个新对象,同时递归地复制嵌套对象。也就是说,深拷贝会创建所有对象的完整副本,包括所有的嵌套对象。深拷贝的数据完全不共享。外层的对象和内部的元素都拷贝了一遍
import copy # 导入copy模块
l1 = [1, 2, 3, [4, 5, 6]] # 定义一个嵌套列表
l2 = copy.deepcopy(l1) # 深拷贝
print('l1', l1)
print('l2', l2)
print('l1[3]的内存地址:', id(l1[3]))
print('l2[3]的内存地址:', id(l2[3]))
往列表添加元素
l1.append(8)
print('l1', l1)
print('l2', l2)
# 往嵌套列表增加元素
l1[3].append(7)
print('l1', l1)
print('l2', l2)
print('l1[3]的内存地址:', id(l1[3]))
print('l2[3]的内存地址:', id(l2[3]))
深拷贝数据变化只影响数据本身,跟原来的对象没有关系
总结
-
浅拷贝:
- 只复制对象本身,嵌套对象仍然引用原始对象。
- 使用
copy.copy()
。
-
深拷贝:
- 递归复制所有嵌套对象,创建完整的独立副本。
- 使用
copy.deepcopy()
。
可变对象
含义:存储空间保存的数据允许被修改,但是内存地址不会改变,这种数据就是可变类型
常见的可变类型:
- 列表(List)
- 字典(Dictionary)
- 集合(Set)
列表
l1 = [1, 2, 3, 4]
print('l1的原内存地址:', id(l1))
l1.append(5)
print(l1)
print('l1的现内存地址:', id(l1))
# 原内存地址与现内存地址相同
字典
dic = {'name': 'elysia', 'age': 18}
print(dic, id(dic))
dic['name'] = 'seele'
print(dic, id(dic))
# 原内存地址与现内存地址相同
集合
set = {1, 2, 3, 4, 5}
print(set, id(set))
set.remove(3)
print(set, id(set))
# 原内存地址与现内存地址相同
不可变对象
含义:变量相应的值不能被修改,如果修改就会生成一个新的值从而分配新的内存空间
常见的不可变对象有:
- 整数(Integer)
- 浮点数(Float)
- 字符串(String)
- 元组(Tuple)
整型
n = 10 # 整型
print('int原地址:', n, id(n))
n = 15
print('int修改后的地址:', n, id(n))
#内存地址不一样,修改n的值就会生成新的值,重新赋值给变量n
字符串
name = 'elysia' #字符串类型
print('str原地址:', id(name))
name = 'seele'
print('str修改后的地址:', id(name))
元组
name = ('e','l','y','s','i','a')
print('tuple原地址:', id(name))
name = ('s','e','e','l','e')
print('tuple修改后的地址:', id(name))
注意:前面的深浅拷贝只针对可变对象,不可变对象不支持,也没有拷贝的说法
影响:
- 性能:由于不可变对象的每次修改都需要创建新对象,因此在处理大量数据时,性能可能会受到影响。
- 哈希:不可变对象可以作为字典的键,因为它们的哈希值在其生命周期内是稳定的。可变对象不能作为字典的键。
- 多线程安全:不可变对象在多线程环境下更安全,因为它们的值不能被改变
可变与不可变对象的区别
特性 | 可变对象 | 不可变对象 |
---|---|---|
修改内容 | 可以在原地修改内容 | 无法修改,任何修改都会创建新对象 |
内存地址变化 | 地址保持不变 | 修改后地址会变化 |
使用场景 | 适合需要频繁修改的场景 | 适合需要保证数据不被改变的场景 |