为何已有bar键时dict.get仍触发KeyError?最优方案是什么?
问题原因
这问题跟get或setdefault方法本身没关系,核心是Python的参数求值规则:不管函数最终用不用得上某个参数,参数对应的表达式都会提前计算完。
看你的代码,thing.get("bar", no_bar(thing))执行时,Python会先算no_bar(thing),再把结果传给get的第二个参数。而你的thing字典里只有bar没有foo,所以调用no_bar(thing)直接触发了KeyError——这时候get还没开始判断bar是否存在呢。setdefault也是同样的道理,第二个参数会被提前求值。
解决方案
方案1:先判断键是否存在(最稳妥)
直接检查bar在不在字典里,存在就取值,不存在再计算推导值:
thing = {"bar": 2} def no_bar(thing): return thing["foo"] bar_value = thing["bar"] if "bar" in thing else no_bar(thing)
这个方法没任何歧义,哪怕bar的值是None、0这类假值也能正确处理。
方案2:get+后续判断(避免重复写键名)
如果不想重复写"bar",可以先用get拿值,再判断是否为None——但要注意:如果业务里bar本身可能被设为None,这个方法会误判,把存在的None当成不存在去推导:
bar_value = thing.get("bar") if bar_value is None: bar_value = no_bar(thing)
方案3:用lambda实现延迟求值
如果一定要用get的默认参数来实现延迟计算,可以把推导逻辑包成lambda,拿到后再调用:
bar_value = thing.get("bar", lambda: no_bar(thing))()
当bar存在时,get返回对应值;不存在时,返回lambda对象,我们再调用它执行推导逻辑,这样就避免了提前计算。
关于你提到的“默认值设为None再推导”
这个方案是可行的,但有个前提:你的bar键不会被设置为None。如果业务场景里bar的值可能是None,那这个方法会误判,这时候还是用方案1更稳妥。
内容的提问来源于stack exchange,提问作者TheRobbie72
相关产品推荐
相关产品推荐

