【发布时间】:2021-12-12 17:11:30
【问题描述】:
我正在使用 ijson 来解析大型 JSON。我有这段代码,它应该给我一个dict 对应于相关 JSON 字段的值:
def parse_kvitems(kv_gen, key_list):
results = {}
for key in key_list:
results[key] = (v for k, v in kv_gen if k == key)
return results
with zipfile.ZipFile(fr'{directory}\{file}', 'r') as zipObj:
# Get a list of all archived file names from the zip
listOfFileNames = zipObj.namelist()
# Iterate over the file names
for fileName in listOfFileNames:
# Check filename endswith csv. dont extract, ijson wants bytes input and json.loads can run into memory issues with smash jsons.No documentation available
if fileName.endswith('.json'):
# Extract a single file from zip
with zipObj.open(fileName) as f:
#HERE:
records = ijson.kvitems(f, 'records.item')
data_list = ['id', 'features', 'modules', 'dbxrefs', 'description']
parsed_records = parse_kvitems(records, data_list) --> give me a dict of dict values that fall under the json headings in data_list
我认为 kvitems 对象就像一个生成器,只通过一次运行(我得到了 'id' 的预期值,但 parsed_records 中的其他 data_list 键是空的)。
为了解决这个问题,我尝试列出重复的 kv_gen 的列表:
def parse_kvitems(kv_gen, key_list):
kv_list = [kv_gen] * len(key_list) #this bit
results = {}
for key, kv_gen in zip(key_list, kv_list):
results[key] = (v for k, v in kv_gen if k == key)
return results
这给了我同样的错误。我认为可变性可能是这里的罪魁祸首,但我不能在 kvitems 对象上使用 copy 来查看这是否可以解决问题。
然后我尝试使用itertools.cycle(),但这似乎以我不理解的方式工作:
def parse_kvitems(kv_gen, key_list):
infinite_kvitems = itertools.cycle(kv_gen)
results = {}
for key in key_list:
results[key] = (v for k, v in infinite_kvitems if k == key)
return results
此外,以下内容也有效(从某种意义上说,它给我的值与我在使用json.load() 加载 JSON 时看到的值相匹配):
records = ijson.kvitems(f, 'records.item')
ids = (v for k, v in records if k == 'id')
features = (v for k, v in records if k == 'features')
modules = (v for k, v in records if k == 'modules')
我只是对为什么我的函数不感兴趣,特别是当记录对象在上面多次运行时...
为罗德里戈编辑
但是,您并没有展示您是如何找到最终字典的 有 id 的值,但没有其他键的值。我假设它只是 因为您正在迭代 首先是 parse_records['id'] 值。当你这样做时,生成器 然后计算表达式,底层的 kvitems 生成器是 筋疲力尽。
是的,这是正确的 - 我将每个 val 转换为一个列表以检查每个键是否有一个包含相同数量项目的生成器,因为我担心下游 zip 操作可能会截断某些值,如果它们的对象多于最小的发电机。
我没有转换为函数中的列表,因为我认为生成器会是一个更好的返回对象(内存密集型等),然后我可以将其转换为函数外部所需的列表。
您说您的最后一段代码按预期工作。这是 只有一点让我感到惊讶,特别是如果你真的,真的检查过 (即评估)您之后的所有三个生成器表达式 创造了他们。如果你能澄清如果是这样的话 有趣的;否则,如果您创建了所有三个生成器表达式, 但是随后评估了其中一个,那么这里就没有惊喜了 (因为“关于结果集合”的解释)。
基本上,当我将项目作为生成器的压缩集合运行并将项目附加到列表时,它给了我所期望的值。但这可能需要更多调查,JSON 非常复杂,所以我可能遗漏了一些东西。
【问题讨论】:
标签: python python-3.x generator ijson