Python 里 immutable和hashable的概念

本文详细介绍了Python中immutable和hashable的概念及其区别。immutable指的是对象创建后无法被修改,而hashable则是指对象可以作为哈希表的索引。文章通过实例展示了不同数据类型的特性,并解释了为什么只有immutable对象才是hashable的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:http://www.lfhacks.com/tech/immutable-hashable-in-python


Python 里有两个紧密联系的概念: immutable和hashable. 都是描述一个对象的属性。

immutable

immutable指对象一经创建,即不可修改。对象是不是immutable取决于数据类型,比如整型(integer)、字符串(string)和元组(tuple)都是immutable,而列表(list)、字典(dictionary)、集合(set)都是mutable。这种不可修改体现在:
1. 字符串不能原位(in-place)修改,而list可以:

>>> string = 'Hello'
>>> string[3:] = 'a'
Traceback (most recent call last):
  File "<>", line 1, in <module>
    string[3:]='a'
TypeError: 'str' object does not support item assignment</font>
>>>
>>> lst=[1,2,3,4]
>>> lst[2:] = [1]
>>> lst
[1, 2, 1]

2. tuple没有方法,而list有很多

>>> t = (1, 2, 3)
>>> t.remove(1)
Traceback (most recent call last):
  File "<>", line 1, in <module>
     t.remove(1)
AttributeError: 'tuple' object has no attribute 'remove'</font>
>>> t.append(1)
Traceback (most recent call last):
  File "<>", line 1, in <module>
  t.append(1)
AttributeError: 'tuple' object has no attribute 'append'
>>> 
>>> l = [1, 2, 3]
>>> l.remove(3)
>>> l
[1, 2]
>>> l.append(3)
>>> l
[1, 2, 3]

于是,immutable的对象可以作为一个固定不变的对象,适合作为哈希表的索引,因而它们是hashable的。

hashable

哈希表是在一个关键字和一个较大的数据之间建立映射的表,能使对一个数据序列的访问过程更加迅速有效。用作查询的关键字必须唯一且固定不变,于是只有immutable的对象才可以作为关键字,也叫hashable.
如上所述,整型(integer)、字符串(string)和元组(tuple)都可以作为关键字,而list不可以。

>>> d = {1:2, 'Ben':123, (1,2,3):456}
>>> d = {1:2, 'Ben':123, [1,2,3]:456}
Traceback (most recent call last):
  File "<>", line 1, in <module>
    d = {1:2, 'Ben':123, [1,2,3]:456}
TypeError: unhashable type: 'list'
immutable与unchangable

tuple是immutable的,即使它包含一个mutable的元素后,仍然可以认为tuple是immutable的,因为他作为一个容器,里面包含对象并没有变化。

>>> t = ([1, 2, 3], 4, 5)
>>> t[0][0] = 0
>>> t
([0, 2, 3], 4, 5)
>>> t[0] = 0
Traceback (most recent call last):
  File "<>", line 1, in <module>
    t[0] = 0
TypeError: 'tuple' object does not support item assignment
前一篇文章: Python 读取csv的某行
后一篇文章: Python 的zip函数
转载请标明 本文链接
<think>嗯,用户想了解Python中可变对象不可变对象的区别、特性示例。首先,我需要回顾一下相关知识,确保自己理解正确。根据引用内容,Python中的对象分为可变不可变两种。不可变对象包括int、float、str、tuple,而可变对象有list、dict、set等。 接下来,我需要整理两者的核心区别。不可变对象一旦创建,内容不能修改,比如尝试修改元组中的元素会报错,如引用3中的例子。而可变对象可以修改内容,比如列表可以通过索引赋值或者调用方法如append来改变,如引用4中的函数参数传递示例。 然后要考虑内存分配机制。不可变对象在内容变化时会创建新对象,如i += 2会生成新的int对象,如引用1所述。而可变对象修改时id不变,引用5中的代码显示列表的id在append前后一致。 还需要注意特殊情况,比如元组中包含列表的情况。虽然元组本身不可变,但内部的列表是可变的,所以可以修改列表的元素,如引用2提到的。 另外,函数参数传递时的行为差异也很重要。不可变对象作为参数时,函数内的修改不会影响原变量,而可变对象的修改会影响原变量,如引用45中的示例。 用户可能还想知道如何判断一个对象是否可变,可以通过尝试修改或者使用hash函数,因为不可变对象是可哈希的。 最后,应用场景方面,不可变对象适合作为字典的键或需要数据安全的情况,可变对象用于需要频繁修改的数据结构。需要确保这些点都覆盖到,并且用清晰的例子说明,帮助用户理解。</think>### Python可变对象与不可变对象的区别、特性及示例 #### 一、核心区别对比 | 特性 | 不可变对象 (Immutable) | 可变对象 (Mutable) | |--------------------|--------------------------------|---------------------------| | **内存分配机制** | 修改时创建新对象 | 原地修改,id保持不变 | | **典型类型** | `int`, `float`, `str`, `tuple` | `list`, `dict`, `set` | | **哈希支持** | 可哈希(可用作字典键) | 不可哈希 | | **参数传递特性** | 函数内修改不改变原始值 | 函数内修改会影响原始值 | | **赋值操作特性** | `=`赋值创建新对象 | `=`赋值创建引用(同id) | #### 二、不可变对象的特性验证 1. **字符串修改实验**: ```python s = "hello" print(id(s)) # 输出: 140000000 s += " world" # 创建新对象 print(id(s)) # 输出: 150000000 (新地址) ``` 修改字符串时会产生新对象[^1] 2. **元组特殊场景**: ```python t = (1, [2, 3]) t[1].append(4) # 允许修改元组内的可变对象 print(t) # (1, [2, 3, 4]) [^2] ``` #### 三、可变对象的典型行为 1. **列表原地修改**: ```python lst = [1, 2, 3] print(id(lst)) # 输出: 160000000 lst.append(4) # 原地修改 print(id(lst)) # 输出: 160000000 (地址不变) [^5] ``` 2. **字典键值更新**: ```python d = {'a': 1} d['b'] = 2 # 直接添加新键 print(d) # {'a': 1, 'b': 2} ``` #### 四、函数参数传递差异 1. **不可变对象传参**: ```python def modify(num): num += 10 x = 5 modify(x) print(x) # 仍为5 [^1] ``` 2. **可变对象传参**: ```python def append_element(lst): lst.append(4) my_list = [1,2,3] append_element(my_list) print(my_list) # [1,2,3,4] [^4] ``` #### 五、判断对象可变性的方法 1. **哈希测试法**: ```python hash("test") # 正常执行 hash([1,2]) # 报错 TypeError ``` 2. **类型识别法**: ```python from collections.abc import Hashable print(isinstance((1,2), Hashable)) # True print(isinstance([1,2], Hashable)) # False ``` #### 六、应用场景建议 1. **使用不可变对象**: - 字典的键值(`tuple`可用作键) - 多线程环境下的安全数据 - 需要保证数据完整性的场景 2. **使用可变对象**: - 动态数据集合处理 - 需要高效内存操作的场景 - 状态需要持续更新的对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值