我正在使用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)
返回None
它只将 k 添加到列表的末尾
要修复它,您可以将其拆分为两行
result.append(k)
result.extend(extract_dict_keys(v))
如前所述,错误来自在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']
正如其他答案所指出的,append
返回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']
追加返回 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]