仅实现__getitem__不够,还需补充__len__、__iter__和keys方法才能模拟字典基本行为;__getitem__不应捕获KeyError,须严格遵循字典协议抛出异常。

直接说结论:用 __getitem__ 模拟字典行为,核心是让实例支持 obj[key] 语法,但它本身不提供 .keys()、.items() 或 in 检查——这些得额外实现,否则会报 TypeError: argument of type 'YourClass' is not iterable 或类似错误。
为什么只写 __getitem__ 不够?
Python 的字典协议(Mapping Protocol)不是单靠 __getitem__ 定义的。内置函数如 dict(obj)、for k in obj、k in obj 都依赖 __iter__ 和 __len__;dict(obj) 还会尝试调用 obj.keys(),而默认没有该方法就会失败。
常见错误现象:
-
for k in my_obj:→TypeError: 'MyDict' object is not iterable -
list(my_obj):→ 同上 -
'a' in my_obj:→TypeError: argument of type 'MyDict' is not iterable(即使__getitem__能取到'a') -
dict(my_obj):→AttributeError: 'MyDict' object has no attribute 'keys'
最小可用字典模拟要补哪几个方法?
仅靠 __getitem__ + 下列三个方法,就能通过大部分字典常用操作:
立即学习“Python免费学习笔记(深入)”;
-
__len__(self):返回键数量,支撑len(obj)和部分内置逻辑 -
__iter__(self):返回键的迭代器,支撑for、list(obj)、k in obj -
keys(self):返回键视图或列表,支撑dict(obj)、obj.keys()
示例骨架:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
class MyDict:
def __init__(self, data=None):
self._data = data or {}
<pre class="brush:php;toolbar:false;">def __getitem__(self, key):
return self._data[key] # 不捕获 KeyError,保持字典语义
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def keys(self):
return self._data.keys() # 返回 dict_keys 更符合预期
这样之后:dict(MyDict({'x': 1})) → {'x': 1},'x' in MyDict({'x': 1}) → True,都正常了。
__getitem__ 里要不要自己处理 KeyError?
不要主动吞掉。标准字典在键不存在时抛 KeyError,这是协议的一部分。如果你在 __getitem__ 里返回默认值或静默忽略,会导致 dict(obj) 失败(它内部会遍历 keys() 再逐个 __getitem__,但不会容忍“键声称存在却取不到”的情况),也会让使用者误判数据完整性。
正确做法:
- 键存在 → 返回值
- 键不存在 → 让底层
self._data[key]自己抛KeyError,或显式raise KeyError(key) - 需要默认值?用
.get(key, default)方法,别塞进__getitem__
性能提示:避免在 __getitem__ 中做耗时计算或 I/O,因为 in 操作、dict() 构造等都可能隐式触发它。
真正麻烦的是嵌套结构或动态键生成场景——这时 __iter__ 和 keys() 的实现逻辑必须和 __getitem__ 严格一致,否则会出现“能取到的键,却遍历不出来”这种反直觉问题。

















