
本文讲解如何正确遍历由空列表和含字典的列表组成的复杂嵌套结构(如 plates),精准定位并提取每个字典中 'sources' 键下的 RA、Dec 等数据,避免误用 Pandas 导致逻辑失效。
本文讲解如何正确遍历由空列表和含字典的列表组成的复杂嵌套结构(如 `plates`),精准定位并提取每个字典中 `'sources'` 键下的 ra、dec 等数据,避免误用 pandas 导致逻辑失效。
在处理类似 plates = [[], [], [{'plate ID': '193a', ..., 'sources': [...]}], [...]...] 这类混合了空列表与字典的嵌套结构时,一个常见误区是直接将整个列表转为 pandas.DataFrame 并尝试用 .iterrows() 遍历——这不仅低效,更会导致逻辑失败:因为 plates 是列表的列表,其每一行(即 row)实际是某个子列表(如 [] 或 [{'plate ID': ..., 'sources': [...]}]),而 row.keys() 会调用列表对象的 keys() 方法(不存在),或在空列表/非字典类型上触发 AttributeError 或始终返回 False,因此 'sources' in row.keys() 永远不成立。
正确的做法是放弃 Pandas,采用原生 Python 的双层循环,逐层解构嵌套结构:
- 外层循环遍历
plates中的每个子列表(记为lst); - 内层循环遍历该子列表中的每个元素(记为
dic),并判断它是否为含'sources'键的字典。
以下是推荐的简洁、高效、可读性强的实现:
matched_plates = []
matches_sources_ra = []
matches_sources_dec = []
for lst in plates: # 遍历外层列表:每个元素是一个子列表
for dic in lst: # 遍历子列表:每个元素可能是字典或 None/空项
if isinstance(dic, dict) and 'sources' in dic:
print(dic['plate ID'])
matched_plates.append([dic['plate ID'], len(dic['sources'])])
# 提取第一个 source 的 RA (索引1) 和 Dec (索引2)
if dic['sources']: # 安全检查:确保 sources 非空
matches_sources_ra.append(dic['sources'][0][1])
matches_sources_dec.append(dic['sources'][0][2])✅ 关键改进点说明:
-
去除 Pandas 依赖:
plates本质是层级明确的嵌套容器,Pandas 的 DataFrame 强制将不规则结构对齐为二维表,反而掩盖了真实数据拓扑,造成row类型混淆; -
显式类型检查:添加
isinstance(dic, dict)可防御性规避因数据异常(如None、字符串等)导致的TypeError; -
空值防护:在访问
dic['sources'][0]前校验if dic['sources'],防止IndexError; -
语义清晰:循环变量名
lst/dic直观反映数据结构层级,便于维护。
运行后将准确输出:
193a 194b
且生成结果:
matched_plates # [['193a', 2], ['194b', 2]] matches_sources_ra # [99.28418829069784, 99.28418829069784] matches_sources_dec # [11.821604434173034, 11.821604434173034]
? 进阶建议:若需提取所有 sources 而非仅首个,可改用嵌套推导式:
all_sources = [
(d['plate ID'], src[0], src[1], src[2]) # ID, source_id, ra, dec
for lst in plates
for d in lst
if isinstance(d, dict) and 'sources' in d
for src in d['sources']
]总之,面对不规则嵌套结构,请优先信任 Python 原生迭代能力——它更轻量、更可控、也更贴近数据本意。

















