python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python不可变数据类型

Python中不可变数据类型int, float, str, bool详解

作者:乖巧的妹子

这篇文章深入浅出解析Python中int、str、float、bool等不可变数据类型的核心特性,帮你理解对象标识、值比较与内存缓存机制,并对比可变类型,让你的代码更安全高效,需要的朋友可以参考下

1. 什么是不可变数据类型?

在 Python 中,不可变数据类型指的是对象一旦被创建,其值(或状态)就不能被改变。如果尝试修改一个不可变对象,Python 实际上会创建一个新的对象,而不是在原有对象上直接修改。

Python 中常见的不可变数据类型包括:

本文将重点讨论前四种最基础、最常用的不可变类型。

2. 整数(int)的不可变性

整数是 Python 中最基本的数值类型之一,它完全不可变。

示例代码

# 示例 1:整数不可变验证
a = 10
print(f"a 的 id: {id(a)}")  # 输出 a 的内存地址

# 尝试“修改”a
a = a + 5
print(f"修改后 a 的值: {a}")
print(f"修改后 a 的 id: {id(a)}")  # id 已改变,说明是新对象

# 示例 2:小整数缓存(Python 优化)
b = 10
c = 10
print(f"b 的 id: {id(b)}")
print(f"c 的 id: {id(c)}")
print(f"b 和 c 是同一个对象吗?{b is c}")  # 通常为 True(-5 到 256 范围内)

示例 3:链式赋值与内存分配

a = b = 4 # a 和 b 都指向同一个整数对象 4
print(f"初始状态: a={a}, b={b}“)
print(f"a is b: {a is b}”) # True,指向同一对象
print(f"id(a): {id(a)}, id(b): {id(b)}")

修改 b 的值

b = 5 # 为 b 创建新的整数对象 5,a 仍然指向 4
print(f"\n修改 b 后: a={a}, b={b}“)
print(f"a is b: {a is b}”) # False,指向不同对象
print(f"id(a): {id(a)}, id(b): {id(b)}“)
print(f"id(4): {id(4)}, id(5): {id(5)}”)

验证小整数缓存

c = 4
print(f"\nc = 4, id©: {id©}“)
print(f"a is c: {a is c}”) # True,因为 4 在小整数缓存范围内

关键特性

3. 浮点数(float)的不可变性

浮点数同样是不可变类型,所有浮点运算都会产生新对象。

示例代码

# 示例 1:浮点数不可变验证
x = 3.14
print(f"初始 x 的 id: {id(x)}")

x = x * 2
print(f"计算后 x 的值: {x}")
print(f"计算后 x 的 id: {id(x)}")  # id 改变,新对象

# 示例 2:浮点数精度问题(与不可变性无关但重要)
print(0.1 + 0.2 == 0.3)  # False,浮点数精度问题
print(f"0.1 + 0.2 = {0.1 + 0.2}")  # 0.30000000000000004

关键特性

4. 字符串(str)的不可变性

字符串是 Python 中最常用的不可变类型之一,所有字符串操作都返回新字符串。

示例代码

# 示例 1:字符串不可变验证
s = "Hello"
print(f"初始 s 的 id: {id(s)}")

# 尝试修改字符串(实际创建新对象)
s = s + " World!"
print(f"修改后 s: {s}")
print(f"修改后 s 的 id: {id(s)}")  # id 改变

# 示例 2:字符串方法返回新对象
text = "Python"
upper_text = text.upper()
print(f"原字符串: {text}, id: {id(text)}")
print(f"大写后: {upper_text}, id: {id(upper_text)}")
print(f"是同一个对象吗?{text is upper_text}")  # False

# 示例 3:字符串索引访问(只读)
word = "immutable"
try:
    word[0] = "I"  # 尝试修改第一个字符
except TypeError as e:
    print(f"错误: {e}")  # 'str' object does not support item assignment

关键特性

5. 布尔值(bool)的不可变性

布尔值是特殊的整数子类(True 相当于 1,False 相当于 0),同样不可变。

示例代码

# 示例 1:布尔值不可变验证
flag = True
print(f"初始 flag 的 id: {id(flag)}")

# 布尔值本身不可变,但可以重新赋值
flag = False
print(f"重新赋值后 flag: {flag}")
print(f"重新赋值后 flag 的 id: {id(flag)}")  # id 改变,指向 False 单例

# 示例 2:布尔值是单例对象
a = True
b = True
c = False
d = False

print(f"a is b: {a is b}")  # True,同一对象
print(f"c is d: {c is d}")  # True,同一对象
print(f"id(True): {id(True)}")
print(f"id(False): {id(False)}")

关键特性

6. 不可变性的优势与注意事项

优势

  1. 线程安全:不可变对象可以在多线程环境中安全共享,无需加锁
  2. 哈希支持:不可变对象可哈希,可作为字典的键或集合的元素
  3. 缓存友好:相同值的不可变对象可以被缓存和重用
  4. 易于推理:对象状态不会意外改变,代码更可预测

注意事项

  1. 内存开销:频繁修改会创建大量新对象,可能增加内存压力
  2. 性能考虑:大量字符串拼接使用 join() 而非 +
  3. 容器中的不可变对象:列表中的不可变元素可以被替换,但元素本身不变

示例:字典键必须是不可变类型

# 有效:使用不可变类型作为键
valid_dict = {
    "name": "Alice",      # str 键
    42: "Answer",         # int 键
    (1, 2): "tuple key",  # tuple 键(不可变)
    True: "Boolean key"   # bool 键
}

# 无效:尝试使用可变类型作为键
try:
    invalid_dict = {[1, 2]: "list key"}  # 列表不可哈希
except TypeError as e:
    print(f"错误: {e}")  # unhashable type: 'list'

7. 总结

Python 的不可变数据类型(int, float, str, bool)是语言的基础构建块。理解它们的不可变性对于:

  1. 编写高效代码:避免不必要的对象创建
  2. 调试程序:理解对象标识(id())与值(value)的区别
  3. 设计数据结构:正确使用字典键和集合元素
  4. 并发编程:利用不可变性实现线程安全

记住关键原则:对不可变对象的"修改"操作,实际上创建了新对象。这一特性使得 Python 代码更加安全、可预测,同时也提醒我们在性能敏感的场景中要注意对象创建的开销。

8. 进一步学习

可变数据类型:list,dict,set

与不可变类型相反,Python 中的可变数据类型允许在创建后修改其内容,而无需创建新对象。

列表(list)

my_list = [1, 2, 3]
print(f"初始 id: {id(my_list)}")  # 初始内存地址

# 修改列表内容
my_list.append(4)
my_list[0] = 100
print(f"修改后列表: {my_list}")
print(f"修改后 id: {id(my_list)}")  # id 不变,说明是同一个对象

字典(dict)

my_dict = {"name": "Alice", "age": 25}
print(f"初始 id: {id(my_dict)}")

# 修改字典
my_dict["age"] = 26
my_dict["city"] = "Beijing"
print(f"修改后字典: {my_dict}")
print(f"修改后 id: {id(my_dict)}")  # id 不变

集合(set)

my_set = {1, 2, 3}
print(f"初始 id: {id(my_set)}")

# 修改集合
my_set.add(4)
my_set.remove(2)
print(f"修改后集合: {my_set}")
print(f"修改后 id: {id(my_set)}")  # id 不变

关键区别

浅拷贝与深拷贝:copy.copy()vscopy.deepcopy()

当需要复制可变对象时,理解拷贝的层次至关重要。

浅拷贝(Shallow Copy)

import copy

original = [[1, 2], [3, 4]]
shallow = copy.copy(original)

print(f"original id: {id(original)}")
print(f"shallow id: {id(shallow)}")  # 外层列表是新对象
print(f"original[0] is shallow[0]: {original[0] is shallow[0]}")  # True,内层列表是同一对象

# 修改浅拷贝的内层列表会影响原对象
shallow[0].append(99)
print(f"修改后 original: {original}")  # [[1, 2, 99], [3, 4]]
print(f"修改后 shallow: {shallow}")    # [[1, 2, 99], [3, 4]]

深拷贝(Deep Copy)

import copy

original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)

print(f"original id: {id(original)}")
print(f"deep id: {id(deep)}")  # 外层列表是新对象
print(f"original[0] is deep[0]: {original[0] is deep[0]}")  # False,内层列表也是新对象

# 修改深拷贝不会影响原对象
deep[0].append(99)
print(f"修改后 original: {original}")  # [[1, 2], [3, 4]],保持不变
print(f"修改后 deep: {deep}")          # [[1, 2, 99], [3, 4]]

使用场景

id()函数:查看对象内存地址

id() 函数返回对象的唯一标识符(通常是内存地址),用于判断两个变量是否指向同一个对象。

# 不可变对象示例
a = 100
b = 100
c = 200
d = 200

print(f"id(a): {id(a)}, id(b): {id(b)}")
print(f"a is b: {a is b}")  # True(小整数缓存)
print(f"id(c): {id(c)}, id(d): {id(d)}")
print(f"c is d: {c is d}")  # False(大整数无缓存)

# 可变对象示例
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1

print(f"\nid(list1): {id(list1)}")
print(f"id(list2): {id(list2)}")
print(f"id(list3): {id(list3)}")
print(f"list1 is list2: {list1 is list2}")  # False,内容相同但不是同一对象
print(f"list1 is list3: {list1 is list3}")  # True,指向同一对象

重要提示

is与==的区别:对象标识 vs 值相等

这是 Python 中容易混淆但非常重要的概念。

is 运算符:检查两个变量是否指向同一个对象(比较对象标识)
== 运算符:检查两个对象的值是否相等(比较对象内容)

# 示例 1:不可变对象(小整数)
x = 256
y = 256
print(f"x == y: {x == y}")  # True,值相等
print(f"x is y: {x is y}")  # True,小整数缓存指向同一对象

# 示例 2:不可变对象(大整数)
a = 1000
b = 1000
print(f"\na == b: {a == b}")  # True,值相等
print(f"a is b: {a is b}")    # False,大整数无缓存,不同对象

# 示例 3:可变对象
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1

print(f"\nlist1 == list2: {list1 == list2}")  # True,内容相同
print(f"list1 is list2: {list1 is list2}")    # False,不同对象
print(f"list1 is list3: {list1 is list3}")    # True,同一对象

# 示例 4:特殊值
print(f"\nNone == None: {None == None}")      # True
print(f"None is None: {None is None}")        # True,None 是单例

print(f"True == 1: {True == 1}")              # True,值相等
print(f"True is 1: {True is 1}")              # False,不同类型

使用建议

  1. 比较值是否相等时,使用 ==
  2. 检查是否为 None 时,总是使用 isis not
  3. 检查两个变量是否指向同一对象时,使用 is
  4. 对于布尔值 True/False,通常使用 == 比较值,除非明确需要检查对象标识

性能考虑is 通常比 == 更快,因为它只比较内存地址,而不需要比较对象内容。

以上就是Python中不可变数据类型int, float, str, bool详解的详细内容,更多关于Python不可变数据类型的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文