Python嵌套playlist结构按索引序列插入属性值实现方案
嵌套播放列表结构属性赋值实现方案
现有结构与需求
当前定义的播放列表根节点结构如下:
self.playlist = { "property_1": value_1, "property_2": value_2, # ... 其余自定义属性 "items": [] }
结构规则:items数组中存储的所有子元素,均和self.playlist为完全相同的结构。
需要实现的赋值功能入参为:
- 目标路径序列
playlist_items_sequence:序列首个元素固定为0,代表根节点self.playlist,后续元素为每层items数组的索引值 - 待写入属性名
property_n - 待写入属性值
value_n
赋值规则示例: - 路径为
[0,2,7]时,等价执行逻辑:self.playlist["items"][2]["items"][7]["property_n"] = value_n - 路径为
[0,1,4,0]时,等价执行逻辑:self.playlist["items"][1]["items"][4]["items"][0]["property_n"] = value_n
最初尝试使用eval()/exec()拼接动态字符串实现功能,但希望找到更安全、不依赖动态代码执行的实现方案。
此前遍历方案的问题说明
你之前编写的逐层遍历引用代码逻辑本身是正确的:
sub_playlist = self.playlist for index_number in playlist_items_sequence[1:]: sub_playlist = sub_playlist["items"][index_number] sub_playlist["property_n"] = value_n
Python中字典是可变类型,遍历过程中sub_playlist始终持有原嵌套结构对应节点的真实引用,对sub_playlist的属性修改会直接同步到原self.playlist对象上,不存在无法更新原变量的问题。如果运行时未生效,一般是路径对应节点不存在触发索引报错、或测试时重新给self.playlist赋值了新对象导致的,和遍历逻辑本身无关。
最优实现(无eval/exec)
直接使用逐层引用遍历即可,eval/exec存在严重的代码注入风险,生产环境应完全避免使用。
如果业务场景需要兼容路径节点不存在的情况,可以增加自动补全空节点的逻辑,完整可直接运行的实现如下:
def set_playlist_attr(self, path_seq, attr_name, attr_val): # 从根节点开始遍历 current_node = self.playlist # 跳过第一个代表根节点的0,遍历后续层索引 for idx in path_seq[1:]: # 索引越界时自动补全空结构,可根据业务需要修改默认属性值 while len(current_node["items"]) <= idx: current_node["items"].append({ "property_1": None, "property_2": None, "items": [] }) # 进入下一层子节点 current_node = current_node["items"][idx] # 到达目标节点后写入属性 current_node[attr_name] = attr_val
用法示例
# 示例1:路径[0,2,7] self.set_playlist_attr([0,2,7], "song_name", "Bohemian Rhapsody") # 等价于 self.playlist["items"][2]["items"][7]["song_name"] = "Bohemian Rhapsody" print(self.playlist["items"][2]["items"][7]["song_name"]) # 输出: Bohemian Rhapsody # 示例2:路径[0,1,4,0] self.set_playlist_attr([0,1,4,0], "duration", 237) # 等价于 self.playlist["items"][1]["items"][4]["items"][0]["duration"] = 237 print(self.playlist["items"][1]["items"][4]["items"][0]["duration"]) # 输出: 237 # 示例3:路径仅为[0],直接修改根节点属性 self.set_playlist_attr([0], "list_name", "My Favorite") print(self.playlist["list_name"]) # 输出: My Favorite
如果业务可以保证传入的路径所有节点均已存在,可以去掉自动补全逻辑,代码更简洁:
def set_playlist_attr(self, path_seq, attr_name, attr_val): current_node = self.playlist for idx in path_seq[1:]: current_node = current_node["items"][idx] current_node[attr_name] = attr_val
内容的提问来源于stack exchange,提问作者Chris P
相关产品推荐
相关产品推荐

