如何优雅定义lambda实现defaultdict缺失键返回最大键对应值且无需引用字典名
解决方案
要实现不引用当前字典外部变量名的逻辑,最优雅的方式是继承defaultdict重写__missing__方法,完全基于实例自身的属性实现逻辑,不受外部变量赋值变更的影响。
基础版(匹配你当前的需求)
from collections import defaultdict class LastKeyDefaultDict(defaultdict): def __missing__(self, key): if not self: raise KeyError("空字典没有可用的默认回退值") # 取最大键对应的值作为默认值 fallback_val = self[max(self.keys())] # 可选:将当前查询的键存入字典,后续查询无需重复走缺省逻辑 self[key] = fallback_val return fallback_val # 测试代码 d = LastKeyDefaultDict() d.update({2010: 10, 2011: 20, 2013: 30 }) for year in [2010, 2011, 2013, 2014]: print(f"{year}: {d[year]}")
运行输出和你现有代码完全一致:
2010: 10 2011: 20 2013: 30 2014: 30
增强版(支持小于最小键的查询回退)
如果需要支持比最小键更小的查询键、以及中间缺失键的就近回退,可以结合二分查找实现更灵活的逻辑:
import bisect from collections import defaultdict class NearestFallbackDict(defaultdict): def __missing__(self, key): if not self: raise KeyError("空字典没有可用的默认回退值") sorted_keys = sorted(self.keys()) # 定位小于等于当前key的最大键位置 pos = bisect.bisect_right(sorted_keys, key) # 比最小键还小时取最小键对应的值,否则取定位到的最近键的值 fallback_key = sorted_keys[0] if pos == 0 else sorted_keys[pos - 1] self[key] = self[fallback_key] return self[key] # 测试全场景 d = NearestFallbackDict() d.update({2010: 10, 2011: 20, 2013: 30 }) for year in [2009, 2010, 2012, 2014]: print(f"{year}: {d[year]}")
运行输出:
2009: 10 2010: 10 2012: 20 2014: 30
极简闭包方案(不想写类的可选方案)
如果不想自定义类,也可以用闭包封装变量,避免lambda引用外部全局变量:
from collections import defaultdict def make_last_key_dict(initial_data=None): instance = defaultdict() instance.default_factory = lambda: instance[max(instance.keys())] if initial_data: instance.update(initial_data) return instance # 使用 d = make_last_key_dict({2010: 10, 2011: 20, 2013: 30 })
内容的提问来源于stack exchange,提问作者divingTobi
相关产品推荐
相关产品推荐

