尝试将字典键检索到列表中时获取 'NoneType' 对象没有属性 'extend' 错误消息

Get 'NoneType' object has no attribute 'extend' error message while trying to retrieve dictionary keys into list

我正在使用 Python 3.8.0 并尝试编写一个函数来提取嵌套词典的所有键并将结果收集到列表中。这是一个例子:

mydict = {"k1":"v1", "k2":"v2", "k3":{"k4":"v4","k5":{"k6":{"k7":"v7","k8":"v8"}}}}

我期望的输出是:

[k1, k2, k3, k4, k5, k7, k8]

这是我定义的递归函数:

def extract_dict_keys(d):
    if isinstance(d, dict):
        result = []
        for k, v in d.items():
            if isinstance(v, dict):
                result.append(k).extend(extract_dict_keys(v))
            else:
                result.append(k)
        return result
    else:
        [None]

但是当我调用 extract_dict_keys(mydict) 时,我收到以下错误消息:

>>> extract_dict_keys(mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in extract_dict_keys
AttributeError: 'NoneType' object has no attribute 'extend'
>>> 

你能指出我的误解吗?我没有看到问题。

result.append(k) returns None 它只将 k 添加到列表的末尾

要修复它,您可以将它分成两行

result.append(k)
result.extend(extract_dict_keys(v)) 

附加returns None 所以你需要像下面这样分隔代码:

def extract_dict_keys(d):
    if isinstance(d, dict):
        result = []
        for k, v in d.items():
            if isinstance(v, dict):
                result.append(k).
                result.extend(extract_dict_keys(v))
            else:
                result.append(k)
        return result
    else:
        [None]

正如其他答案所指出的,append returns None,所以你不能做 result.append(k).extend(extract_dict_keys(v)),因为它扩展了 NoneType,而不是一个列表。您需要先添加密钥,然后继续递归。

一种简单的方法是在输入 if 之前添加密钥,以检查值是否属于 dict 类型:

mydict = {"k1":"v1", "k2":"v2", "k3":{"k4":"v4","k5":{"k6":{"k7":"v7","k8":"v8"}}}}

def extract_dict_keys(d):
    keys = []

    for k, v in d.items():
        keys.append(k)
        if isinstance(v, dict):
            keys.extend(extract_dict_keys(v))

    return keys

print(extract_dict_keys(mydict))
# ['k1', 'k2', 'k3', 'k4', 'k5', 'k6', 'k7', 'k8']

如前所述,错误来自对 append() 的结果调用 extend(),即 None

用生成器编写这种递归代码通常会更好。这有几个好处:不需要维护内部状态,节省内存,代码更简单:

mydict = {"k1":"v1", "k2":"v2", "k3":{"k4":"v4","k5":{"k6":{"k7":"v7","k8":"v8"}}}}

def extract_dict_keys(d):
    if not isinstance(d, dict):
        return
    for k, v in d.items():
        yield k
        yield from extract_dict_keys(v)

list(extract_dict_keys(mydict))
# ['k1', 'k2', 'k3', 'k4', 'k5', 'k6', 'k7', 'k8']