应将 d.has_key('key') 替换为 'key' in d,这是唯一可靠且无兼容风险的修复方式;Python 3 已移除该方法,in 操作符更高效、统一、符合语言规范。

Python 3 报 AttributeError: 'dict' object has no attribute 'has_key' 怎么办
直接改:把 d.has_key('key') 换成 'key' in d。这是唯一可靠、无兼容风险的修复方式。
这个错误不是你写错了,是 Python 3 主动删掉了该方法。任何试图“恢复”has_key 的补丁(比如 monkey patch 或封装函数)都只是掩盖问题,不解决实质。
- 别用
try/except AttributeError包裹旧写法——它掩盖了版本迁移事实,后续维护更难 - 别在代码里写
if hasattr(d, 'has_key'):——Python 2.2+ 早就支持in,没必要为老版本妥协 - 如果必须跑 Python 2 和 3,统一用
'key' in d即可,无需额外判断
为什么 in 比 has_key() 更快
in 是语言级操作符,直接走字典的哈希查找路径;has_key() 是方法调用,要先查属性、再进 C 函数入口、再做同样哈希查找——多一层间接。
实测(10 万次查找):'x' in d 约 0.035 μs,d.has_key('x') 约 0.072 μs(Python 2 下),差距接近一倍。
立即学习“Python免费学习笔记(深入)”;
-
d.keys()更慢:它会生成一个新视图(Python 3)或列表(Python 2),再遍历查找——完全不可取 -
in在所有内置容器(dict、set、list)中语义一致,但性能差异极大:对dict是 O(1),对list是 O(n)
in 不仅能查字典,还能查其他结构
同一个语法,'a' in my_dict、'a' in my_set、'a' in my_list 都合法。而 has_key() 只属于 dict,没法复用到 set 或自定义容器上。
如果你写了个类想支持键存在性检查,只要实现 __contains__ 方法,in 就自动可用;但没人会去给每个类加个 has_key 方法。
- 标准库中几乎所有容器类型都实现了
__contains__,in是统一接口 -
has_key()是历史包袱:它只服务dict,且和get()、pop()等方法风格不一致(后者都带括号,has_key却像英语动词)
容易被忽略的边界点:in 查的是键,不是值
新手常误以为 'value' in d 能查值是否存在——它查的是键。查值得用 'value' in d.values(),但注意这会遍历全部值,O(n) 开销。
另外,None、False、空字符串等“falsy”值作为键时,in 判断完全不受影响,它只看键是否存在,不看键对应的值是什么。
- 不要混淆
key in d和d.get(key) is not None:后者失败于值本身是None的情况 -
in对不可哈希类型(如list、dict)作键会直接报TypeError,这是好事——提前暴露设计问题


















