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

 更新时间:2026年07月16日 09:21:42   作者:乖巧的妹子  
这篇文章深入浅出解析Python中int、str、float、bool等不可变数据类型的核心特性,帮你理解对象标识、值比较与内存缓存机制,并对比可变类型,让你的代码更安全高效,需要的朋友可以参考下

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

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

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

  • int(整数)
  • float(浮点数)
  • str(字符串)
  • bool(布尔值)
  • tuple(元组)
  • frozenset(冻结集合)

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

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 在小整数缓存范围内

关键特性

  • 对整数进行任何运算(+, -, *, // 等)都会返回一个新的整数对象
  • Python 对小整数(通常为 -5 到 256)有缓存优化,相同值可能指向同一对象
  • 大整数每次运算都会创建新对象

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

关键特性

  • 浮点运算可能产生精度误差,这是 IEEE 754 标准特性,不是 Python 独有
  • 与整数不同,Python 不会缓存浮点数对象(相同值的浮点数也可能是不同对象)
  • 使用 decimal 模块处理需要精确小数运算的场景

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

关键特性

  • 字符串的所有方法(upper(), lower(), replace(), strip() 等)都返回新字符串
  • 字符串支持索引访问,但只能读取不能修改
  • 字符串拼接(+)或格式化(f-string, format())都会创建新对象
  • 对于大量字符串拼接,建议使用 join() 方法提高性能

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)}")

关键特性

  • TrueFalse 是单例对象,全局唯一
  • 布尔值是 int 的子类:isinstance(True, int) 返回 True
  • 布尔运算(and, or, not)返回新的布尔值

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 不变

关键区别

  • 可变对象:修改内容时,对象标识(id())不变
  • 不可变对象:任何"修改"都会创建新对象,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]]

使用场景

  • copy.copy():当对象只包含不可变元素或你明确知道需要共享内部引用时
  • copy.deepcopy():当对象包含嵌套的可变对象,且你需要完全独立的副本时

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,指向同一对象

重要提示

  • id() 的值在对象的生命周期内是唯一的
  • 两个对象的 id() 相同意味着它们是同一个对象
  • CPython 中 id() 返回的是对象的内存地址,但这不是语言规范要求

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不可变数据类型的资料请关注脚本之家其它相关文章!

相关文章

  • python打包exe文件并隐藏执行CMD命令窗口问题

    python打包exe文件并隐藏执行CMD命令窗口问题

    这篇文章主要介绍了python打包exe文件并隐藏执行CMD命令窗口问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Python datacompy 找出两个DataFrames不同的地方

    Python datacompy 找出两个DataFrames不同的地方

    本文主要介绍了Python datacompy 找出两个DataFrames不同的地方,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2022-05-05
  • Python+wxPython实现文件内容搜索工具

    Python+wxPython实现文件内容搜索工具

    在本篇文章中,我们将介绍如何使用 wxPython 库创建一个简单的文件搜索工具,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-08-08
  • Python中的set可变集合与frozenset不可变集合的终极指南

    Python中的set可变集合与frozenset不可变集合的终极指南

    这篇文章主要为大家详细介绍了Python中set与frozenset的区别与应用,set是可变集合,支持增删元素和自动去重,frozenset是不可变集合,下面小编就来和大家详细介绍一下吧
    2026-02-02
  • python序列解包应用示例详解

    python序列解包应用示例详解

    这篇文章主要为大家介绍了python序列解包应用场景示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • 对Matlab中共轭、转置和共轭装置的区别说明

    对Matlab中共轭、转置和共轭装置的区别说明

    这篇文章主要介绍了对Matlab中共轭、转置和共轭装置的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • 使用Python实现牛顿法求极值

    使用Python实现牛顿法求极值

    今天小编就为大家分享一篇使用Python实现牛顿法求极值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • Python批量下载图片的实现步骤

    Python批量下载图片的实现步骤

    在我们日常生活中,有时候进入一个网站后,发现大量的图片,比如说一些好看的素材,以及我以前非常喜欢看的风景图片,想要下载下来怎么办?难道我一张张去复制?这有点不现实,所以本文给大家介绍了Python批量下载图片的实现步骤,需要的朋友可以参考下
    2025-10-10
  • Python反编译的两种实现方式

    Python反编译的两种实现方式

    这篇文章主要介绍了Python反编译的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 实例解析Python设计模式编程之桥接模式的运用

    实例解析Python设计模式编程之桥接模式的运用

    这篇文章主要介绍了Python设计模式编程之桥接模式的运用,桥接模式主张把抽象部分与它的实现部分分离,需要的朋友可以参考下
    2016-03-03

最新评论