为什么Python对KeyError和IndexError的处理不同?

0 投票
1 回答
2787 浏览
提问于 2025-04-18 11:45

我在尝试一些一行代码的解决方案,目的是定义一个变量,前提是这个变量还不存在。结果我发现,Python对字典和列表/元组的处理方式不一样。这些错误在我看来是相似的,所以我有点困惑,为什么会有这样的差异。

字典的KeyError处理

existing_dict = {"spam": 1, "eggs": 2}
existing_dict["foo"] = existing_dict["foo"] if not KeyError else 3

返回 {"spam": 1, "eggs": 2, "foo": 3}

注意,我在左右两边都引用了一个不存在的键;Python在这两种情况下处理KeyError都没有问题。

列表的IndexError处理(元组也是如此)

existing_list = ["spam","eggs"]
existing_list[2] = existing_list[2] if not IndexError else ["foo"]

返回 IndexError: list assignment index out of range

解决这个特定错误并不难(这里有答案),但我很好奇为什么这两种情况会有差别。在这两种情况下,似乎在赋值的两边都有错误,但只有一个“如果不”错误捕捉。

1 个回答

5

这两种情况下KeyErrorIndexError都是,并且它们都是“真”的:

>>> bool(KeyError)
True
>>> bool(IndexError)
True

在Python中,所有的类对象都被视为“真”,具体可以参考真值测试

你不能用条件表达式来测试异常;对于你给出的两个例子else的值总是会被选中,然后被赋值;你的测试实际上等同于:

existing_dict["foo"] = 3
existing_list[2] = ["foo"]

你应该使用异常处理,或者使用长度测试。

异常的产生是因为对列表索引的赋值只有在索引已经存在时才有效:

>>> empty = []
>>> empty[0] = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

这只是字典和列表工作方式的不同;列表可以添加元素,这样索引的数量会增加。而字典则不行(没有顺序),所以要添加一个新的键值对,你需要直接给它赋值。另一方面,如果列表支持任意索引的赋值,那么中间的所有索引会发生什么呢?如果列表是空的,但你给索引42赋值,那索引0到41会怎样?

你可以用try/except来捕获异常:

try:
    existing_list[2] = "foo"
except IndexError:
    existing.append('foo')

这会替换索引2处的现有值,或者如果索引还不存在,则会添加新的值。

你也可以尝试测试长度:

if len(existing_list) <= 3:
    existing_list.append('foo')

只有在元素数量少于3个时,才会添加新的元素。

对于字典,测试键是否存在:

if 'foo' not in existing_dict:
    existing_dict['foo'] = 3

撰写回答