Python 中主要数据类型分类及特性总结(附:可哈希 (Hashable) 与 不可哈希 (Unhashable) 详解)
本文系统总结了Python中的数据类型分类及特性。
主要内容包括:
- 数据类型分类:基本类型(int/float/str等)、序列类型(list/tuple/range)、映射类型(dict)、集合类型(set/frozenset)和二进制序列类型(bytes/bytearray);
- 类型特性对比:可变性(list/dict可变,tuple/str不可变)、有序性(list有序,set无序)和可哈希性(可哈希类型可作为字典键);
- 可哈希性详解:定义了可哈希对象的条件(不可变、有哈希值、可比较相等),列举了常见可哈希与不可哈希类型,并说明了可哈希性的实际应用场景;
- 类型转换与判断方法。
全文通过对比表格和示例代码,清晰展示了Python数据类型的核心特性与使用要点。
Python 中主要数据类型分类总结
一、基本数据类型
| 类型 | 名称 | 示例 | 特点 | 可变性 |
|---|---|---|---|---|
int | 整数 | 42,-10,0b1010 | 任意精度,无范围限制 | 不可变 |
float | 浮点数 | 3.14,-0.5,1.2e-5 | 双精度浮点数 | 不可变 |
complex | 复数 | 3+4j,1.2-0.5j | 实部+虚部 | 不可变 |
bool | 布尔型 | True,False | 只有两个值,是int子类 | 不可变 |
str | 字符串 | "Hello",'Python',"""多行""" | Unicode字符序列 | 不可变 |
NoneType | 空值 | None | 表示空或不存在的值 | 不可变 |
二、序列类型
| 类型 | 名称 | 示例 | 特点 | 可变性 | 有序性 |
|---|---|---|---|---|---|
list | 列表 | [1, 2, 3],['a', 'b'] | 可存放任意类型,功能强大 | 可变 | 有序 |
tuple | 元组 | (1, 2, 3),('a',) | 轻量级不可变序列 | 不可变 | 有序 |
range | 范围 | range(5),range(1,10,2) | 整数序列,节省内存 | 不可变 | 有序 |
三、映射类型
| 类型 | 名称 | 示例 | 特点 | 可变性 | 有序性 |
|---|---|---|---|---|---|
dict | 字典 | {'name':'Tom', 'age':18} | 键值对存储,键必须可哈希 | 可变 | Python3.7+有序 |
四、集合类型
| 类型 | 名称 | 示例 | 特点 | 可变性 | 有序性 |
|---|---|---|---|---|---|
set | 集合 | {1, 2, 3},set([1,2,2]) | 元素唯一,去重 | 可变 | 无序 |
frozenset | 冻结集合 | frozenset([1,2,3]) | 不可变版本的集合 | 不可变 | 无序 |
五、二进制序列类型
| 类型 | 名称 | 示例 | 特点 | 可变性 |
|---|---|---|---|---|
bytes | 字节串 | b'hello',bytes([65,66]) | 0-255的整数序列 | 不可变 |
bytearray | 字节数组 | bytearray(b'hello') | 可修改的字节序列 | 可变 |
memoryview | 内存视图 | memoryview(b'hello') | 直接访问内存数据 | 可变 |
六、各类型对比速查
可变 vs 不可变
| 可变类型 (Mutable) | 不可变类型 (Immutable) |
|---|---|
list | int |
dict | float |
set | bool |
bytearray | str |
| 自定义类实例(默认) | tuple |
frozenset | |
bytes | |
range |
有序 vs 无序
| 有序类型 (Ordered) | 无序类型 (Unordered) |
|---|---|
list | set |
tuple | frozenset |
str | dict(Python3.7前) |
range | |
dict(Python3.7+) |
可哈希 vs 不可哈希
| 可哈希类型(可作为字典键) | 不可哈希类型 |
|---|---|
int,float,bool | list |
str | dict |
tuple(元素都哈希) | set |
frozenset | bytearray |
None |
七、类型判断与转换
| 操作 | 示例 | 说明 |
|---|---|---|
| 类型判断 | isinstance(5, int) | 推荐使用,支持继承 |
| 类型判断 | type(5) is int | 精确判断,不考虑继承 |
| 类型转换 | list((1,2,3)) | 元组转列表 |
| 类型转换 | tuple([1,2,3]) | 列表转元组 |
| 类型转换 | set([1,2,2,3]) | 列表转集合(去重) |
| 类型转换 | dict([(1,'a'),(2,'b')]) | 键值对序列转字典 |
| 类型转换 | str(123) | 转字符串 |
| 类型转换 | int("123") | 字符串转整数 |
八、各类型字面量速查
| 类型 | 字面量示例 |
|---|---|
int | 42,0xFF(十六进制),0o12(八进制),0b1010(二进制) |
float | 3.14,1.2e-5 |
complex | 3+4j |
str | '单引号',"双引号",'''三单引号''',"""三双引号""" |
list | [1, 2, 3] |
tuple | (1, 2, 3)或1, 2, 3 |
dict | {'key': 'value'} |
set | {1, 2, 3} |
bool | True,False |
None | None |
提示:Python 是动态强类型语言,变量无需声明类型,但不同类型之间通常不会自动转换。
可哈希 (Hashable) 与 不可哈希 (Unhashable) 详解
一、什么是哈希?
哈希是将任意大小的数据(如字符串、数字)通过哈希函数转换成固定长度的唯一标识(哈希值)的过程。
python
# 哈希值示例 hash(42) # 输出: 42 hash("hello") # 输出: -2091548855179221912 hash((1,2,3)) # 输出: 529344067295497451二、可哈希类型的特征
一个对象是可哈希的,需要满足以下条件:
✅有哈希值- 实现
__hash__()方法✅可比较相等- 实现
__eq__()方法✅不可变- 创建后内容不能改变
三、常见可哈希与不可哈希类型
| 类型 | 可哈希? | 原因 |
|---|---|---|
int | ✅ 是 | 不可变 |
float | ✅ 是 | 不可变 |
bool | ✅ 是 | 不可变 |
str | ✅ 是 | 不可变 |
tuple | ✅ 是 | 不可变(前提:内部元素也都可哈希) |
frozenset | ✅ 是 | 不可变 |
None | ✅ 是 | 单例对象 |
list | ❌ 否 | 可变,内容可改变 |
dict | ❌ 否 | 可变 |
set | ❌ 否 | 可变 |
bytearray | ❌ 否 | 可变 |
四、为什么需要可哈希?
可哈希对象可以:
作为字典的键(dict key)
作为集合的元素(set element)
python
# ✅ 正确:使用可哈希类型作为字典键 d = { 1: "整数键", # int 可哈希 "name": "字符串键", # str 可哈希 (1,2): "元组键" # tuple 可哈希 } # ✅ 正确:使用可哈希类型作为集合元素 s = {1, 2, 3, "a", (4,5)} # ❌ 错误:使用不可哈希类型作为字典键 d = {[1,2]: "列表键"} # TypeError: unhashable type: 'list' # ❌ 错误:使用不可哈希类型作为集合元素 s = {[1,2], [3,4]} # TypeError: unhashable type: 'list'五、特殊情况:元组的可哈希性
元组本身不可变,但它的可哈希性取决于内部元素:
python
# ✅ 元组内都是可哈希元素 → 元组可哈希 t1 = (1, 2, "a") hash(t1) # 成功 # ❌ 元组内包含不可哈希元素 → 元组不可哈希 t2 = (1, [2, 3], "a") hash(t2) # TypeError: unhashable type: 'list'六、如何判断对象是否可哈希?
python
# 方法1:使用 hash() 函数测试 def is_hashable(obj): try: hash(obj) return True except TypeError: return False print(is_hashable(42)) # True print(is_hashable("hello")) # True print(is_hashable([1,2])) # False print(is_hashable({1,2})) # False # 方法2:使用 collections.abc.Hashable from collections.abc import Hashable print(isinstance(42, Hashable)) # True print(isinstance([1,2], Hashable)) # False七、实际应用场景
场景1:去重时的问题
python
data = [1, 2, 2, [3,4], [3,4], 5] # ❌ 错误:直接对包含列表的列表用 set() 去重 unique = set(data) # TypeError: unhashable type: 'list' # ✅ 解决:转换为可哈希形式 unique = set(tuple(x) if isinstance(x, list) else x for x in data) # 结果: {1, 2, 5, (3, 4)}场景2:缓存/记忆化
python
from functools import lru_cache @lru_cache(maxsize=128) def fibonacci(n): """缓存需要参数可哈希""" if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) # ✅ 参数 int 可哈希,可以缓存 fibonacci(10) # ❌ 如果参数是列表,不能使用 lru_cache场景3:字典统计频率
python
# ✅ 使用可哈希类型作为键 freq = {} words = ["apple", "banana", "apple"] for word in words: freq[word] = freq.get(word, 0) + 1 # word 是 str,可哈希 # ❌ 不能统计列表的频率 data = [[1,2], [1,2], [3,4]] freq = {} for item in data: freq[item] = freq.get(item, 0) + 1 # TypeError八、如何让自定义类可哈希?
python
class Point: def __init__(self, x, y): self.x = x self.y = y # 实现 __hash__ 方法 def __hash__(self): return hash((self.x, self.y)) # 实现 __eq__ 方法 def __eq__(self, other): if not isinstance(other, Point): return False return self.x == other.x and self.y == other.y # 使其不可变(可选) def __setattr__(self, name, value): if hasattr(self, name): raise AttributeError(f"Cannot modify {name}") super().__setattr__(name, value) # 现在 Point 对象可以作为字典键 p1 = Point(1, 2) p2 = Point(1, 2) d = {p1: "A点"} print(d[p2]) # "A点",因为 p1 == p2九、快速总结表
| 特性 | 可哈希 | 不可哈希 |
|---|---|---|
| 有哈希值 | ✅ | ❌ |
| 可比较相等 | ✅ | 可能可以 |
| 不可变 | ✅ | 通常可变 |
| 可作字典键 | ✅ | ❌ |
| 可作集合元素 | ✅ | ❌ |
| 典型代表 | int,str,tuple | list,dict,set |
记忆口诀:可变不可哈希,不可变可哈希。字典的键和集合的元素,都必须是可哈希。
