当前位置: 代码网 > it编程>前端脚本>Python > Python中不可变数据类型int, float, str, bool详解

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

2026年07月16日 Python 我要评论
1. 什么是不可变数据类型?在 python 中,不可变数据类型指的是对象一旦被创建,其值(或状态)就不能被改变。如果尝试修改一个不可变对象,python 实际上会创建一个新的对象,而不是在原有对象上

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不可变数据类型的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com