You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python带可变默认参数的函数可哈希而含可变元素的元组不可?

元组和函数的哈希判定逻辑核心差异

1. 元组的哈希逻辑

元组是值语义的不可变容器,它的哈希计算和相等判定完全对齐:

  • 元组的__hash__方法会递归遍历所有元素,把所有元素的哈希值组合计算得到最终结果
  • 如果元组内包含任何不可哈希的元素(比如列表),递归计算哈希时就会抛出错误,导致整个元组不可哈希
  • 元组的相等判定是「所有元素的值都相等」,因此只要元组可以哈希,就保证值相同的元组哈希值相同,符合哈希的一致性要求

对应示例的报错原因就是元组内的列表不可哈希,递归计算失败:

In [1]: t = (1,2,[3])                                                           
In [2]: hash(t)                                                                 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-8a01c6d8dba1> in <module>
----> 1 hash(t)
TypeError: unhashable type: 'list'

2. 函数的哈希逻辑

函数是身份语义的对象,哈希计算和相等判定都只和对象身份绑定:

  • 函数属于内置function类的实例,该类的__hash__方法默认基于对象的内存ID计算,完全不依赖任何内部属性(包括存储默认参数的__defaults__属性、函数代码本身以外的其他属性)
  • 函数的相等判定默认也是「是否是同一个内存地址的对象」,和内部属性的变化无关
  • 哪怕修改了函数的默认参数(本质是修改了f.__defaults__属性的值),只要还是同一个函数对象,它的内存ID不会变,因此哈希值也不会变,完全符合哈希的一致性要求

对应示例中函数可哈希的原因就是哈希只依赖身份,和可变默认参数无关:

In [5]: def f(a: List = [1]): 
   ...:     a += a 
   ...:     return a 
   ...:                                                                         
In [6]: hash(f)                                                                 
Out[6]: 8731603958411

两者设计差异的原因

这种差异是Python的设计取舍决定的:

  • 元组的定位之一是作为不可变的复合键用于字典、集合等场景,因此需要按值判定相等和哈希
  • 函数的定位是可调用对象,绝大多数场景下不需要按内部属性的不同区分不同的函数对象,默认按身份判定哈希和相等的成本更低、更符合使用习惯

内容的提问来源于stack exchange,提问作者Amir reza Riahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 22:30:05