1 回答

TA貢獻(xiàn)1798條經(jīng)驗(yàn) 獲得超7個(gè)贊
這是一組遞歸生成器,可用于搜索由字典和列表組成的對(duì)象。find_key產(chǎn)生一個(gè)元組,其中包含字典鍵列表和導(dǎo)致您傳入的鍵的列表索引;元組還包含與該鍵關(guān)聯(lián)的值。因?yàn)樗且粋€(gè)生成器,所以如果需要的話,如果對(duì)象包含多個(gè)匹配鍵,它將找到所有匹配鍵。
def find_key(obj, key):
if isinstance(obj, dict):
yield from iter_dict(obj, key, [])
elif isinstance(obj, list):
yield from iter_list(obj, key, [])
def iter_dict(d, key, indices):
for k, v in d.items():
if k == key:
yield indices + [k], v
if isinstance(v, dict):
yield from iter_dict(v, key, indices + [k])
elif isinstance(v, list):
yield from iter_list(v, key, indices + [k])
def iter_list(seq, key, indices):
for k, v in enumerate(seq):
if isinstance(v, dict):
yield from iter_dict(v, key, indices + [k])
elif isinstance(v, list):
yield from iter_list(v, key, indices + [k])
# test
data = {
'1_data': {
'4_data': [
{'5_data': 'hooray'},
{'3_data': 'hooray2'}
],
'2_data': []
}
}
for t in find_key(data, '3_data'):
print(t)
輸出
(['1_data', '4_data', 1, '3_data'], 'hooray2')
要獲取單個(gè)鍵列表,可以傳遞find_key給該next函數(shù)。如果要使用鍵列表來(lái)獲取關(guān)聯(lián)的值,則可以使用簡(jiǎn)單的for循環(huán)。
seq, val = next(find_key(data, '3_data'))
print('seq:', seq, 'val:', val)
obj = data
for k in seq:
obj = obj[k]
print('obj:', obj, obj == val)
輸出
seq: ['1_data', '4_data', 1, '3_data'] val: hooray2
obj: hooray2 True
如果密鑰可能丟失,請(qǐng)?zhí)峁﹏ext適當(dāng)?shù)哪J(rèn)元組。例如:
seq, val = next(find_key(data, '6_data'), ([], None))
print('seq:', seq, 'val:', val)
if seq:
obj = data
for k in seq:
obj = obj[k]
print('obj:', obj, obj == val)
輸出
seq: [] val: None
請(qǐng)注意,此代碼是針對(duì)Python 3的。要在Python 2上運(yùn)行,您需要替換所有yield from語(yǔ)句,例如replace
yield from iter_dict(obj, key, [])
與
for u in iter_dict(obj, key, []):
yield u
怎么運(yùn)行的
要了解此代碼的工作原理,您需要熟悉遞歸和Python 生成器。您可能還會(huì)發(fā)現(xiàn)此頁(yè)面有幫助:了解Python中的生成器;在線上也有各種Python生成器教程。
json.load或返回的Python對(duì)象json.loads通常是字典,但也可以是列表。我們將該對(duì)象find_key與objarg一起傳遞給生成器,作為key我們想要定位的字符串。find_key然后根據(jù)需要調(diào)用iter_dict或iter_list,將它們,對(duì)象,鍵和一個(gè)空列表傳遞給它們,該空列表indices用于收集dict鍵和列出指向所需鍵的索引。
iter_dict在其ddict arg 的頂層迭代每個(gè)(k,v)對(duì)。如果k與我們要查找的鍵匹配,則會(huì)生成當(dāng)前indices列表k并附加到當(dāng)前列表以及相關(guān)的值。因?yàn)閕ter_dict是遞歸的,所以產(chǎn)生的(索引列表,值)對(duì)將傳遞到遞歸的上一個(gè)級(jí)別,最終使它們到達(dá)find_key并到達(dá)調(diào)用的代碼find_key。請(qǐng)注意,這是遞歸的“基本情況”:這是確定此遞歸路徑是否指向所需鍵的代碼的一部分。如果遞歸路徑找不到與我們要查找的鍵匹配的鍵,則該遞歸路徑將不會(huì)添加任何內(nèi)容,indices并且它將終止而不會(huì)產(chǎn)生任何結(jié)果。
如果當(dāng)前v是一個(gè)字典,那么我們需要檢查它包含的所有(鍵,值)對(duì)。我們通過(guò)對(duì)進(jìn)行遞歸調(diào)用來(lái)實(shí)現(xiàn)iter_dict,將v其作為起始對(duì)象和當(dāng)前indices列表進(jìn)行傳遞。如果當(dāng)前v是一個(gè)列表,我們改為調(diào)用iter_list,將相同的參數(shù)傳遞給它。
iter_listiter_dict除了列表不包含任何鍵,它只包含值外,其工作方式與之類(lèi)似。因此,我們不執(zhí)行k == key測(cè)試,而是遞歸到原始列表包含的所有字典或列表。
該過(guò)程的最終結(jié)果是,當(dāng)我們進(jìn)行迭代時(shí),find_key我們獲得(索引,值)對(duì),其中每個(gè)indices列表是dict鍵的序列和列表索引,這些鍵成功地終止于帶有所需鍵的dict項(xiàng)中,并且value是關(guān)聯(lián)的值用那個(gè)特定的鑰匙。
如果您想查看此代碼的其他示例,請(qǐng)參閱如何修改嵌套Json的鍵以及如何從python的字典中選擇深度嵌套的key:values。
還要看看我的新的,更簡(jiǎn)化的show_indices功能。
分享編輯
添加回答
舉報(bào)