资讯动态

深入理解 Python 不可变数据类型:int, float, str, bool

发布时间:2026/8/10 12:31:30 来源:尧图企业网站定制
1. 什么是不可变数据类型在 Python 中不可变数据类型指的是对象一旦被创建其值或状态就不能被改变。如果尝试修改一个不可变对象Python 实际上会创建一个新的对象而不是在原有对象上直接修改。Python 中常见的不可变数据类型包括int整数float浮点数str字符串bool布尔值tuple元组frozenset冻结集合本文将重点讨论前四种最基础、最常用的不可变类型。2. 整数int的不可变性整数是 Python 中最基本的数值类型之一它完全不可变。示例代码# 示例 1整数不可变验证a10print(fa 的 id:{id(a)})# 输出 a 的内存地址# 尝试“修改”aaa5print(f修改后 a 的值:{a})print(f修改后 a 的 id:{id(a)})# id 已改变说明是新对象# 示例 2小整数缓存Python 优化b10c10print(fb 的 id:{id(b)})print(fc 的 id:{id(c)})print(fb 和 c 是同一个对象吗{bisc})# 通常为 True-5 到 256 范围内示例 3链式赋值与内存分配a b 4 # a 和 b 都指向同一个整数对象 4print(f初始状态: a{a}, b{b}“)print(fa is b: {a is b}”) # True指向同一对象print(fid(a): {id(a)}, id(b): {id(b)})修改 b 的值b 5 # 为 b 创建新的整数对象 5a 仍然指向 4print(f\n修改 b 后: a{a}, b{b}“)print(fa is b: {a is b}”) # False指向不同对象print(fid(a): {id(a)}, id(b): {id(b)}“)print(fid(4): {id(4)}, id(5): {id(5)}”)验证小整数缓存c 4print(f\nc 4, id©: {id©}“)print(fa is c: {a is c}”) # True因为 4 在小整数缓存范围内关键特性对整数进行任何运算,-,*,//等都会返回一个新的整数对象Python 对小整数通常为 -5 到 256有缓存优化相同值可能指向同一对象大整数每次运算都会创建新对象3. 浮点数float的不可变性浮点数同样是不可变类型所有浮点运算都会产生新对象。示例代码# 示例 1浮点数不可变验证x3.14print(f初始 x 的 id:{id(x)})xx*2print(f计算后 x 的值:{x})print(f计算后 x 的 id:{id(x)})# id 改变新对象# 示例 2浮点数精度问题与不可变性无关但重要print(0.10.20.3)# False浮点数精度问题print(f0.1 0.2 {0.10.2})# 0.30000000000000004关键特性浮点运算可能产生精度误差这是 IEEE 754 标准特性不是 Python 独有与整数不同Python 不会缓存浮点数对象相同值的浮点数也可能是不同对象使用decimal模块处理需要精确小数运算的场景4. 字符串str的不可变性字符串是 Python 中最常用的不可变类型之一所有字符串操作都返回新字符串。示例代码# 示例 1字符串不可变验证sHelloprint(f初始 s 的 id:{id(s)})# 尝试修改字符串实际创建新对象ss World!print(f修改后 s:{s})print(f修改后 s 的 id:{id(s)})# id 改变# 示例 2字符串方法返回新对象textPythonupper_texttext.upper()print(f原字符串:{text}, id:{id(text)})print(f大写后:{upper_text}, id:{id(upper_text)})print(f是同一个对象吗{textisupper_text})# False# 示例 3字符串索引访问只读wordimmutabletry:word[0]I# 尝试修改第一个字符exceptTypeErrorase:print(f错误:{e})# str object does not support item assignment关键特性字符串的所有方法upper(),lower(),replace(),strip()等都返回新字符串字符串支持索引访问但只能读取不能修改字符串拼接或格式化f-string,format()都会创建新对象对于大量字符串拼接建议使用join()方法提高性能5. 布尔值bool的不可变性布尔值是特殊的整数子类True相当于 1False相当于 0同样不可变。示例代码# 示例 1布尔值不可变验证flagTrueprint(f初始 flag 的 id:{id(flag)})# 布尔值本身不可变但可以重新赋值flagFalseprint(f重新赋值后 flag:{flag})print(f重新赋值后 flag 的 id:{id(flag)})# id 改变指向 False 单例# 示例 2布尔值是单例对象aTruebTruecFalsedFalseprint(fa is b:{aisb})# True同一对象print(fc is d:{cisd})# True同一对象print(fid(True):{id(True)})print(fid(False):{id(False)})关键特性True和False是单例对象全局唯一布尔值是int的子类isinstance(True, int)返回True布尔运算and,or,not返回新的布尔值6. 不可变性的优势与注意事项优势线程安全不可变对象可以在多线程环境中安全共享无需加锁哈希支持不可变对象可哈希可作为字典的键或集合的元素缓存友好相同值的不可变对象可以被缓存和重用易于推理对象状态不会意外改变代码更可预测注意事项内存开销频繁修改会创建大量新对象可能增加内存压力性能考虑大量字符串拼接使用join()而非容器中的不可变对象列表中的不可变元素可以被替换但元素本身不变示例字典键必须是不可变类型# 有效使用不可变类型作为键valid_dict{name:Alice,# str 键42:Answer,# int 键(1,2):tuple key,# tuple 键不可变True:Boolean key# bool 键}# 无效尝试使用可变类型作为键try:invalid_dict{[1,2]:list key}# 列表不可哈希exceptTypeErrorase:print(f错误:{e})# unhashable type: list7. 总结Python 的不可变数据类型int,float,str,bool是语言的基础构建块。理解它们的不可变性对于编写高效代码避免不必要的对象创建调试程序理解对象标识id()与值value的区别设计数据结构正确使用字典键和集合元素并发编程利用不可变性实现线程安全记住关键原则对不可变对象的修改操作实际上创建了新对象。这一特性使得 Python 代码更加安全、可预测同时也提醒我们在性能敏感的场景中要注意对象创建的开销。8. 进一步学习可变数据类型list,dict,set与不可变类型相反Python 中的可变数据类型允许在创建后修改其内容而无需创建新对象。列表listmy_list[1,2,3]print(f初始 id:{id(my_list)})# 初始内存地址# 修改列表内容my_list.append(4)my_list[0]100print(f修改后列表:{my_list})print(f修改后 id:{id(my_list)})# id 不变说明是同一个对象字典dictmy_dict{name:Alice,age:25}print(f初始 id:{id(my_dict)})# 修改字典my_dict[age]26my_dict[city]Beijingprint(f修改后字典:{my_dict})print(f修改后 id:{id(my_dict)})# id 不变集合setmy_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 Copyimportcopy original[[1,2],[3,4]]shallowcopy.copy(original)print(foriginal id:{id(original)})print(fshallow id:{id(shallow)})# 外层列表是新对象print(foriginal[0] is shallow[0]:{original[0]isshallow[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 Copyimportcopy original[[1,2],[3,4]]deepcopy.deepcopy(original)print(foriginal id:{id(original)})print(fdeep id:{id(deep)})# 外层列表是新对象print(foriginal[0] is deep[0]:{original[0]isdeep[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()函数返回对象的唯一标识符通常是内存地址用于判断两个变量是否指向同一个对象。# 不可变对象示例a100b100c200d200print(fid(a):{id(a)}, id(b):{id(b)})print(fa is b:{aisb})# True小整数缓存print(fid(c):{id(c)}, id(d):{id(d)})print(fc is d:{cisd})# False大整数无缓存# 可变对象示例list1[1,2,3]list2[1,2,3]list3list1print(f\nid(list1):{id(list1)})print(fid(list2):{id(list2)})print(fid(list3):{id(list3)})print(flist1 is list2:{list1islist2})# False内容相同但不是同一对象print(flist1 is list3:{list1islist3})# True指向同一对象重要提示id()的值在对象的生命周期内是唯一的两个对象的id()相同意味着它们是同一个对象CPython 中id()返回的是对象的内存地址但这不是语言规范要求is与的区别对象标识 vs 值相等这是 Python 中容易混淆但非常重要的概念。is运算符检查两个变量是否指向同一个对象比较对象标识运算符检查两个对象的值是否相等比较对象内容# 示例 1不可变对象小整数x256y256print(fx y:{xy})# True值相等print(fx is y:{xisy})# True小整数缓存指向同一对象# 示例 2不可变对象大整数a1000b1000print(f\na b:{ab})# True值相等print(fa is b:{aisb})# False大整数无缓存不同对象# 示例 3可变对象list1[1,2,3]list2[1,2,3]list3list1print(f\nlist1 list2:{list1list2})# True内容相同print(flist1 is list2:{list1islist2})# False不同对象print(flist1 is list3:{list1islist3})# True同一对象# 示例 4特殊值print(f\nNone None:{NoneNone})# Trueprint(fNone is None:{NoneisNone})# TrueNone 是单例print(fTrue 1:{True1})# True值相等print(fTrue is 1:{Trueis1})# False不同类型使用建议比较值是否相等时使用检查是否为None时总是使用is或is not检查两个变量是否指向同一对象时使用is对于布尔值True/False通常使用比较值除非明确需要检查对象标识性能考虑is通常比更快因为它只比较内存地址而不需要比较对象内容。rangePython3 range() 函数返回的是一个可迭代对象类型是对象而不是列表类型 所以打印的时候不会打印列表。Python3 list() 函数是对象迭代器可以把 range() 返回的可迭代对象转为一个列表返回的变量类型为列表。Python2 range() 函数返回的是列表。函数语法range(stop)range(start, stop[, step])参数说明start: 计数从 start 开始。默认是从 0 开始。例如 range(5) 等价于 range(0 5)stop: 计数到 stop 结束但不包括 stop。例如range(0 5) 是 [0, 1, 2, 3, 4] 没有 5step步长默认为 1。例如range(0 5) 等价于 range(0, 5, 1)for number in range(6, 1, -1):print(number)for i in range(-10, -100, -30) :print(i)-10-40-70while类型【】 {} {}定义增删查改推导试dictdefaultdict(int) list:解决key不存在的情况默认赋值d {key1 : value1, key2 : value2, key3 : value3 }[表达式 for 变量 in 列表][out_exp_res for out_exp in input_list]或者[表达式 for 变量 in 列表 if 条件][out_exp_res for out_exp in input_list if condition]{ key_expr: value_expr for value in collection }或{ key_expr: value_expr for value in collection if condition }{ expression for item in Sequence }或{ expression for item in Sequence if conditional }装饰器语法糖装饰器通过 语法糖应用在函数定义前解析decorator_function装饰器函数接收原函数wrapper包装函数真正被执行decorator_function等价于函数替换def decorator_function(original_function):def wrapper(*args, **kwargs):# 调用前print(“执行前”)result original_function(*args, **kwargs) # 调用后 print(执行后) return result return wrapperdecorator_functiondef target_function():print(“原函数执行”)调用 target_function() 时实际上执行的是 wrapper()if elif ifif condition_1:statement_block_1elif condition_2:statement_block_2else:statement_block_3try except else finallytry:runoob()except AssertionError as error:print(error)else:try:with open(‘file.log’) as file:read_data file.read()except FileNotFoundError as fnf_error:print(fnf_error)finally:print(‘这句话无论异常是否发生都会执行。’)TypeError操作或函数应用于不适当类型的对象时引发。例如尝试将整数和字符串相加123。ValueError传入有效类型但值不合适的参数时引发。例如尝试将非数字字符串转换为整数1。NameError尝试访问未定义的变量时引发23。IndexError序列索引超出范围时引发。例如尝试访问列表中不存在的索引12。KeyError字典中不存在的键时引发1。ZeroDivisionError尝试除以零时引发12。 IOError尝试读取不存在的文件或无法访问文件时引发2。 ImportError尝试导入不存在的模块或包时引发2。AttributeError尝试访问对象不存在的属性时引发2。KeyboardInterrupt用户中断程序执行时引发。例如按下CtrlC时2。SyntaxError代码不符合Python语法规则时触发。例如缩进错误、未闭合的字符串引号、错误的关键字拼写等3。IndentationError代码的缩进格式不符合语法规范时触发。例如混合使用空格和制表符、缩进层级不一致等3。Python assert断言用于判断一个表达式在表达式条件为 false 的时候触发异常。Python assert断言用于判断一个表达式在表达式条件为 false 的时候触发异常。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价