python 数据类型

可变类型与不可变类型的区别

可变类型 不可变类型
数据类型 list, dict, set, bytearray int, float, bool, str, tuple, frozenset, bytes
特点 1. 修改内容时,对象本身不变,内存地址不变.
2. 不能作为字典的键(因为哈希值会变).
3. 修改变量的值时,其实是 创建了一个新对象.
4. 可以作为字典的键、集合的元素(因为哈希值不会变)
可变类型
不可变类型
# ============================
# 1. 列表(list)是可变类型
# ============================

print("=== 列表示例 ===")
lst = [1, 2, 3]
print("初始列表:", lst, "地址:", id(lst))

lst.append(4)  # 原地修改
print("append 后:", lst, "地址:", id(lst))  # 地址不变

lst[0] = 99  # 修改元素
print("修改元素后:", lst, "地址:", id(lst))  # 地址仍不变

# ============================
# 2. 字典(dict)是可变类型
# ============================

print("\n=== 字典示例 ===")
d = {"a": 1, "b": 2}
print("初始字典:", d, "地址:", id(d))

d["c"] = 3  # 添加键值对
print("添加键后:", d, "地址:", id(d))

d["a"] = 100  # 修改值
print("修改值后:", d, "地址:", id(d))

# ============================
# 3. 集合(set)是可变类型
# ============================

print("\n=== 集合示例 ===")
s = {1, 2, 3}
print("初始集合:", s, "地址:", id(s))

s.add(4)  # 添加元素
print("add 后:", s, "地址:", id(s))

s.remove(2)  # 删除元素
print("remove 后:", s, "地址:", id(s))

# ============================
# 4. 可变类型的引用行为
# ============================

print("\n=== 引用行为示例 ===")
a = [1, 2, 3]
b = a  # b 指向同一个列表
print("a 地址:", id(a))
print("b 地址:", id(b))

b.append(999)
print("修改 b 后 a:", a)  # a 也被修改
print("修改 b 后 b:", b)

# ============================
# 5. 可变类型作为函数参数
# ============================

print("\n=== 函数参数示例 ===")

def modify_list(x):
    x.append("new")  # 原地修改

lst2 = [10, 20]
print("调用前:", lst2)
modify_list(lst2)
print("调用后:", lst2)  # 被修改

# ============================
# 6. 可变类型作为默认参数的陷阱
# ============================

print("\n=== 默认参数陷阱示例 ===")

def add_item(item, container=[]):  # 不推荐
    container.append(item)
    return container

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] 共享了同一个列表!
print(add_item(3))  # [1, 2, 3]
# ============================
# 1. int(整数)是不可变类型
# ============================

print("=== int 示例 ===")
a = 10
print("初始 a:", a, "地址:", id(a))

a = a + 1  # 创建新对象
print("修改后 a:", a, "地址:", id(a))  # 地址变化


# ============================
# 2. float(浮点数)不可变
# ============================

print("\n=== float 示例 ===")
x = 3.14
print("初始 x:", x, "地址:", id(x))

x *= 2  # 创建新对象
print("修改后 x:", x, "地址:", id(x))


# ============================
# 3. bool(布尔)不可变
# ============================

print("\n=== bool 示例 ===")
flag = True
print("flag:", flag, "地址:", id(flag))

flag = not flag  # 新对象
print("修改后 flag:", flag, "地址:", id(flag))


# ============================
# 4. str(字符串)不可变
# ============================

print("\n=== str 示例 ===")
s = "hello"
print("初始 s:", s, "地址:", id(s))

s = s + " world"  # 拼接会创建新字符串
print("拼接后 s:", s, "地址:", id(s))


# ============================
# 5. tuple(元组)不可变
# ============================

print("\n=== tuple 示例 ===")
t = (1, 2, 3)
print("初始 t:", t, "地址:", id(t))

t = t + (4,)  # 拼接生成新元组
print("修改后 t:", t, "地址:", id(t))


# ============================
# 6. frozenset(冻结集合)不可变
# ============================

print("\n=== frozenset 示例 ===")
fs = frozenset([1, 2, 3])
print("初始 fs:", fs, "地址:", id(fs))

fs2 = fs.union([4])  # union 返回新对象
print("union 后 fs2:", fs2, "地址:", id(fs2))
print("原 fs 未变:", fs, "地址:", id(fs))


# ============================
# 7. 不可变类型的引用行为
# ============================

print("\n=== 引用行为示例 ===")
a = 100
b = a  # b 指向同一个对象
print("a 地址:", id(a))
print("b 地址:", id(b))

b = b + 1  # b 指向新对象,不影响 a
print("修改后 a:", a, "地址:", id(a))
print("修改后 b:", b, "地址:", id(b))


# ============================
# 8. 不可变类型作为函数参数
# ============================

print("\n=== 函数参数示例 ===")

def modify_value(x):
    x = x + 10  # 生成新对象,不影响外部变量
    print("函数内部 x:", x, "地址:", id(x))

v = 5
print("调用前 v:", v, "地址:", id(v))
modify_value(v)
print("调用后 v:", v, "地址:", id(v))  # v 不变

python 深拷贝和浅拷贝

浅拷贝 深拷贝
特点 创建一个新的外层对象, 内部的子对象(列表、字典等)仍然是共享引用 创建一个新的外层对象, 递归复制所有内部子对象, 完全独立
场景 1. 内部对象不会被修改.
2. 数据结构简单(如一维列表).
3. 性能要求高(浅拷贝更快).
1. 嵌套结构(列表套字典、字典套列表等).
2. 需要完全独立的数据副本.
3. 避免共享引用导致的“连带修改”.
浅拷贝
深拷贝
import copy

print("=== 基础浅拷贝 ===")
a = [1, 2, [3, 4]]
b = copy.copy(a)

print("a 地址:", id(a))
print("b 地址:", id(b))
print("a[2] 地址:", id(a[2]))
print("b[2] 地址:", id(b[2]))  # 内层列表共享

b[2].append(5)
print("修改 b 后 a:", a)  # a 被影响
print("修改 b 后 b:", b)

print("\n=== 列表浅拷贝方式 ===")
a = [1, 2, [3, 4]]

b1 = a[:]          # 切片
b2 = list(a)       # list() 构造
b3 = copy.copy(a)  # copy.copy()

for name, b in [("b1", b1), ("b2", b2), ("b3", b3)]:
    print(name, "外层地址:", id(b), "内层地址:", id(b[2]))

print("\n=== 字典浅拷贝 ===")
d1 = {"x": 1, "y": [10, 20]}
d2 = d1.copy()

print("d1 地址:", id(d1))
print("d2 地址:", id(d2))
print("d1['y'] 地址:", id(d1["y"]))
print("d2['y'] 地址:", id(d2["y"]))  # 内层共享

d2["y"].append(30)
print("修改 d2 后 d1:", d1)  # d1 被影响
print("修改 d2 后 d2:", d2)

print("\n=== 集合浅拷贝 ===")
s1 = {1, 2, 3}
s2 = s1.copy()

print("s1 地址:", id(s1))
print("s2 地址:", id(s2))

s2.add(4)
print("修改 s2 后 s1:", s1)  # 不影响,因为集合内部没有嵌套
print("修改 s2 后 s2:", s2)

print("\n=== 函数参数中的浅拷贝 ===")

def modify_shallow(lst):
    new_lst = lst[:]  # 浅拷贝
    new_lst[2].append(999)  # 修改内层
    return new_lst

a = [1, 2, [3, 4]]
result = modify_shallow(a)

print("原列表 a:", a)        # 内层被修改
print("返回值 result:", result)
import copy

# 原始数据:包含可变对象
a = [1, [2, 3], {"x": 10}]

# 浅拷贝
b = copy.copy(a)

# 深拷贝
c = copy.deepcopy(a)

# 修改浅拷贝 b
b[1].append(4)
b[2]["x"] = 99

# 修改深拷贝 c
c[1].append(5)
c[2]["x"] = 100

print("a =", a)
print("b =", b)
print("c =", c)

"""
output: 
a = [1, [2, 3, 4], {'x': 99}]
b = [1, [2, 3, 4], {'x': 99}]
c = [1, [2, 3, 5], {'x': 100}]
"""

元组(tuple)

概述