Python:在嵌套字典中查找值的递归函数不断返回 'None'

Python: recursive function to find value in nested dictionary keeps returning 'None'

我有一个包含显微镜采集元数据的嵌套字典,如下所示:

metadata_dict = {Metadata:   {"_text"       :   "\n\n  ",
                              "Core"        :   [{"_text"   :   \n\n  ",
                                                  "Guid"        :   [{"_text"   :   "c..."}],
                                                  "UserID"      :   [{"_text"   :   "xyz"}]
                                                  "AppSW"       :   [{"_text"   :   "xT"}]
                                                  "AppSWVer"    :   [{"_text"   :   "0"}]
                                                }],
                              "Instrument"  :   [{"_text"   :   "\n\n  ",
                                                  "ContrSWVer   :   [{"_text":  :   "10..."}]
                                                   ...

等等(希望缩进让它不那么混乱)。我只需要某些 key/value 对,我正在使用 python 将值获取到可指定的键。 .get() 方法 returns 'None' 无论参数如何,所以我尝试了以下方法遍历字典中的所有值以查找特定键:

def lookup(dic,prop):
    for k, v in dic.items():
        if k == prop:
            if not isinstance(v, dict):
                return v
            else:
                for key, value in v:
                    return value
        elif isinstance(v, dict):
            lookup(v, prop)

调用此方法,e。 G。通过

UserID = lookup(metadata_dict, 'UserID')
print(UserID)

无论参数在字典中的嵌套级别如何,我都只得到 'None' 输出。

This post 似乎解决了同样的问题,但是,在将最后两行更改为

之后
        elif isinstance(v, dict):
            return lookup(v, prop)

我仍然得到 'None' returns。 这可能是由于递归调用第二个参数为 prop 的方法导致方法 运行 v, prop (和 prop 是一个未定义的变量)而不是从初始函数继承参数(示例中的 'UserID')?如果是这样,考虑到 prop 未定义,为什么 return 不是错误?

你可以试试这个,看看是否有效,如果不行,我建议你解释你想要的结果,你可以以数据为例

def lookup(dic, prop):
    res = []
    for item in dic.values():
        if isinstance(item, list):
            for sub_item in item:
                for k, v in sub_item.items():
                    if k == prop:
                        res.append(v)
        elif isinstance(item, dict):
            for k, v in item.items():
                if k == prop:
                    res.append(v)
    return res


metadata_dict = {"Metadata":   {"_text"       :   "\n\n  ",
                              "Core"        :   [{"_text"   :   "\n\n  ",
                                                  "Guid"        :   [{"_text"   :   "c..."}],
                                                  "UserID"      :   [{"_text"   :   "xyz"}],
                                                  "AppSW"       :   [{"_text"   :   "xT"}],
                                                  "AppSWVer"    :   [{"_text"   :   "0"}]
                                                }],
                              "Instrument"  :   [{"_text"   :   "\n\n  ",
                                                  "Guid"        :   [{"_text"   :   "124"}],
                                                  "UserID"      :   [{"_text"   :   "waefe"}],
                                                  "AppSW"       :   [{"_text"   :   "asfa"}],
                                                  "AppSWVer"    :   [{"_text"   :   "21"}]
                                                }]
}}

print(lookup(metadata_dict["Metadata"], "UserID"))

问题是 UserID 在列表 ['Metadata']['Core'] 中。

只有当 v 是一个字典时,你才是递归的。

您可以修改代码来处理该问题:

def lookup(dic, prop):
    for k, v in dic.items():
        if k == prop:
            if not isinstance(v, dict):
                return v
        if isinstance(v, dict):
            return lookup(v, prop)
        if isinstance(v, list):
            for item in v:
                found = lookup(item, prop)
                if found:
                    return found
>>> lookup(metadata_dict, "UserID")
[{'_text': 'xyz'}]

我遗漏了:

else:
    for key, value in v:
        return value

v 是一个字典,所以这应该会引发错误。 return 也将退出该函数 - 因此这只会处理一个值。

如果可以有多个匹配项 - 您可以改用生成器。

def lookup(dic, prop):
    for k, v in dic.items():
        if k == prop:
            if not isinstance(v, dict):
                yield v
        if isinstance(v, dict):
            yield from lookup(v, prop)
        if isinstance(v, list):
            for item in v:
                yield from lookup(item, prop)

输出:

>>> for result in lookup(metadata_dict, "UserID"):
...     print(result)
[{'_text': 'xyz'}]

具有多个值的示例:

>>> for result in lookup({"Foo": [{"UserID": 1}], "Bar": {"Baz":[{"Hi": {"UserID": "2"}}]}}, "UserID"):
...     print(result)
1
2