Python中如何通过动态多段键字符串过滤字典值?
问题
我想通过输入动态键字符串来过滤字典中的指定值,比如键字符串格式为filter_key = "fdd.hello1"或者filter_key = "fdd.hello1.k1.k2.k3"。目前的实现代码仅支持最多2个分隔点的键字符串,如何修改才能适配任意长度的动态键?
现有代码如下:
import operator as op d1 = {'name': 'test1', 'with_child': ['c1', 'c2'], 'fdd': {'hello1': 123, 'hello2': 234}, 'date': '2023-3-10'} filter_key = "fdd.hello1" def filter_value(val, filter_key): dot_count = op.countOf(filter_key, ".") filter_value = "" try: if dot_count == 0: filter_value = d1[filter_key] if dot_count == 1: f1,c1 = filter_key.split(".") filter_value = d1[f1][c1] elif dot_count == 2: f1,c1,c2 = filter_key.split(".") filter_value = d1[f1][c1][c2] except KeyError as e: print("123213123213") return filter_value
解决方案
方法1:循环遍历键路径
把键字符串按.分割成键列表,从字典根节点开始逐层向下访问,直到获取最终值。这种方法逻辑直观,便于调试和扩展额外逻辑。
修改后的代码:
d1 = {'name': 'test1', 'with_child': ['c1', 'c2'], 'fdd': {'hello1': 123, 'hello2': {'k1': {'k2': {'k3': 456}}}}, 'date': '2023-3-10'} def filter_value(data, filter_key): current = data try: keys = filter_key.split(".") for key in keys: # 兼容列表索引(比如"with_child.0"可以取到'c1') current = current[int(key)] if key.isdigit() else current[key] return current except (KeyError, TypeError, IndexError) as e: # 捕获键不存在、节点不可索引、列表越界等错误 print(f"获取值失败:{str(e)}") return "" # 测试示例 print(filter_value(d1, "fdd.hello1")) # 输出123 print(filter_value(d1, "fdd.hello2.k1.k2.k3")) # 输出456 print(filter_value(d1, "with_child.0")) # 输出c1 print(filter_value(d1, "invalid.key")) # 捕获错误并返回空字符串
方法2:用functools.reduce简化代码
利用reduce函数将逐层取值的逻辑压缩为一行代码,适合追求代码精简的场景,底层逻辑和循环法一致。
代码实现:
from functools import reduce import operator d1 = {'name': 'test1', 'with_child': ['c1', 'c2'], 'fdd': {'hello1': 123, 'hello2': {'k1': {'k2': {'k3': 456}}}}, 'date': '2023-3-10'} def get_item(obj, key): # 兼容列表索引的自定义取值函数 return obj[int(key)] if key.isdigit() else obj[key] def filter_value(data, filter_key): try: keys = filter_key.split(".") return reduce(get_item, keys, data) except (KeyError, TypeError, IndexError) as e: print(f"获取值失败:{str(e)}") return "" # 测试示例 print(filter_value(d1, "fdd.hello1")) # 输出123 print(filter_value(d1, "fdd.hello2.k1.k2.k3")) # 输出456
注意点
- 两种方法都扩展了错误捕获范围,不仅处理
KeyError,还覆盖了节点不可索引、列表越界等场景 - 新增了列表索引兼容逻辑,支持类似
"with_child.0"的路径格式
内容的提问来源于stack exchange,提问作者Ershan
相关产品推荐
相关产品推荐

