如何使用点表示法字符串读取Python列表/字典对象的值?
问题:通过点表示法字符串获取嵌套字典/列表中的值
给定以下Python对象(列表嵌套字典):
d = [ { 'props': { 'columns': [ { 'field': 'Hello' } ] } } ]
我希望能用点表示法格式的字符串来获取field的值,比如实现一个类似这样的函数:
get(d, "[0].props.columns[0].field") >>> 'Hello'
我试过把字典转为Python对象来支持点表示法访问,但不知道怎么通过字符串形式的路径来实现取值。目前的代码能支持d[0].props.columns[0].field这种直接访问,但没法解析字符串形式的路径。另外,当前的Dict2Object类初始化不支持直接传入列表,这部分也需要修复。
以下是我当前的代码实现:
import json class Dict2Object: """ @DynamicAttrs 将字典转换为Python对象的类 """ def __init__(self, in_dict): # 类型检查 assert isinstance(in_dict, (dict, list)) # 如果是字典,遍历键值对 if isinstance(in_dict, dict): for key, val in in_dict.items(): # 处理键名:替换连字符、空格为下划线,转为小写 key = translate_string(key) # 如果值是序列类型(列表、元组、集合) if isinstance(val, (list, tuple, set)): # 序列中的字典转为Dict2Object,其他保持原样 setattr( self, key, [Dict2Object(x) if isinstance(x, dict) else x for x in val], ) else: # 非序列值:字典转Dict2Object,其他直接赋值 setattr(self, key, Dict2Object(val) if isinstance(val, dict) else val) def __repr__(self): return "{%s}" % str( ", ".join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.items()) ) def translate_string(string): string = string.replace("-", "_") string = string.replace(" ", "_") string = string.lower() return string d = [ { 'props': { 'columns': [ { 'field': 'Hello' } ] } } ] d_obj = Dict2Object(d[0]) print(d_obj.props.columns[0].field) # 输出: 'Hello'
解决方案
方法1:解析路径字符串直接访问原对象
不需要转换对象,直接解析路径字符串中的索引和属性/键,逐层访问:
def get(obj, path): import re # 拆分路径节点,处理[0]和.的组合情况 nodes = re.split(r'(?<=\])\.|\.(?=\[)|(?<=\w)\.(?=\w)', path) current = obj for node in nodes: if node.startswith('[') and node.endswith(']'): # 处理列表索引 idx = int(node[1:-1]) current = current[idx] else: # 处理字典键或对象属性 if isinstance(current, dict): current = current[node] else: current = getattr(current, node) return current # 测试 print(get(d, "[0].props.columns[0].field")) # 输出: Hello
方法2:改进Dict2Object支持列表,并实现路径解析
先修改Dict2Object让它能处理初始列表,再实现路径解析函数:
class Dict2Object: """ @DynamicAttrs 将字典或列表转换为Python对象的类 """ def __init__(self, data): assert isinstance(data, (dict, list)) if isinstance(data, list): # 列表类型转为包含Dict2Object的列表 self._list = [Dict2Object(item) if isinstance(item, dict) else item for item in data] elif isinstance(data, dict): for key, val in data.items(): key = translate_string(key) if isinstance(val, (list, tuple, set)): setattr(self, key, [Dict2Object(x) if isinstance(x, dict) else x for x in val]) else: setattr(self, key, Dict2Object(val) if isinstance(val, dict) else val) def __getitem__(self, idx): # 支持列表索引访问 if hasattr(self, '_list'): return self._list[idx] raise TypeError("Not a list-like object") def __repr__(self): if hasattr(self, '_list'): return repr(self._list) return "{%s}" % str( ", ".join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.items()) ) def translate_string(string): string = string.replace("-", "_") string = string.replace(" ", "_") string = string.lower() return string def get_obj_value(obj, path): import re nodes = re.split(r'(?<=\])\.|\.(?=\[)|(?<=\w)\.(?=\w)', path) current = obj for node in nodes: if node.startswith('[') and node.endswith(']'): idx = int(node[1:-1]) current = current[idx] else: current = getattr(current, node) return current # 测试 d_obj = Dict2Object(d) print(get_obj_value(d_obj, "[0].props.columns[0].field")) # 输出: Hello
内容的提问来源于stack exchange,提问作者njminchin
相关产品推荐
相关产品推荐

