HOWTO · Python

如何在 Python 中将字典键转换为列表

介绍如何用 list()、循环、列表推导式或解包获取 Python 字典键列表,并说明 dict_keys 视图与列表的区别。

本页内容

要将 Python 字典的键转换为列表,直接使用 list(my_dict) 即可;list(my_dict.keys()) 得到的列表相同。这两种写法都通过 list() 构造函数把键收集到一个新列表中。单独调用 my_dict.keys() 返回的是可迭代的 dict_keys 视图,不能像列表一样按索引取值。需要真正的列表对象时再转换;如果只需遍历键,直接遍历字典通常就够了。

使用 dict.keys() 获取 Python 字典的键

dict.keys() 方法返回当前字典键的视图。修改字典后,视图会反映变化,而从视图创建的列表是一份独立的快照。在 Python 3.7 及更新版本中,遍历字典会按键的插入顺序进行;下面展示的顺序以此为前提。

state_capitals = {
    "California": "Sacramento",
    "Pennsylvania": "Harrisburg",
    "Texas": "Austin",
}

keys_view = state_capitals.keys()
print(keys_view)
for state in keys_view:
    print(state)

keys_list = list(keys_view)
print(keys_list)
print(list(state_capitals))
print(keys_list[0])

state_capitals["Nevada"] = "Carson City"
print(list(keys_view))
print(keys_list)
dict_keys(['California', 'Pennsylvania', 'Texas'])
California
Pennsylvania
Texas
['California', 'Pennsylvania', 'Texas']
['California', 'Pennsylvania', 'Texas']
California
['California', 'Pennsylvania', 'Texas', 'Nevada']
['California', 'Pennsylvania', 'Texas']

list(keys_view) 和 list(state_capitals) 都会创建列表;后一种写法之所以可行,是因为遍历字典时得到的是键。直接对视图使用索引会引发 TypeError。如果字典为空,转换结果是 [];再对这个空列表使用索引则会引发 IndexError。

使用循环获取 Python 字典的键

如果收集键时还需要逐个处理,显式循环很方便。写成 for key in state_capitals:其中 in 关键字不可省略,循环取到的是键,不是值。

state_capitals = {
    "California": "Sacramento",
    "Pennsylvania": "Harrisburg",
    "Texas": "Austin",
}

keys = []
for key in state_capitals:
    keys.append(key)
print(keys)
['California', 'Pennsylvania', 'Texas']

对于空字典,循环一次也不会执行,keys 保持为空。如果只是获取键,无需在循环中做额外处理,list(state_capitals) 更简洁。

使用列表推导式获取 Python 字典的键

列表推导式可以用一行代码完成同样的收集操作。需要筛选键或对每个键进行转换时,这种形式便于扩展;如果只是复制键,用 list() 构造函数更简单。

state_capitals = {
    "California": "Sacramento",
    "Pennsylvania": "Harrisburg",
    "Texas": "Austin",
}

keys = [key for key in state_capitals]
print(keys)
['California', 'Pennsylvania', 'Texas']

字典为空时,这个推导式也会返回 []。

使用 Python 解包运算符 * 获取字典的键

可迭代对象解包语法 * 能将字典的键放入列表字面量,例如 [*state_capitals]。PEP 448 从 Python 3.5 起扩展了解包语法;这里关于版本兼容性的说明依据语法规范,并非在 Python 3.5 上运行示例所得。解包也可用于元组和集合字面量。

state_capitals = {
    "California": "Sacramento",
    "Pennsylvania": "Harrisburg",
    "Texas": "Austin",
}

keys_list = [*state_capitals]
keys_tuple = (*state_capitals,)
keys_set = {*state_capitals}
print(keys_list)
print(keys_tuple)
print(sorted(keys_set))
['California', 'Pennsylvania', 'Texas']
('California', 'Pennsylvania', 'Texas')
['California', 'Pennsylvania', 'Texas']

集合会去除重复元素,但不保证显示顺序;示例用 sorted() 让输出顺序可预测。在 Python 3.7 及更新版本中,列表和元组会保留遍历字典时的键顺序。如果结果必须是列表,请使用列表形式。

比较运行性能

如果转换速度很重要,请用自己的 Python 解释器,以及与实际输入规模相近的字典进行测量。以下脚本会打印 Python 版本,并对同一个含 100 个条目的字典进行测试:每组运行 10,000 次转换,共重复五组;取耗时最短的一组,除以 10,000 后报告每次转换的平均耗时(秒)。每条计时代码都会创建新列表;循环写法在每次转换时也会新建用于存放结果的列表。

import platform
from timeit import repeat

state_capitals = {str(number): number for number in range(100)}
methods = {
    "list(d.keys())": "list(state_capitals.keys())",
    "list(d)": "list(state_capitals)",
    "loop": "keys = []\nfor key in state_capitals:\n    keys.append(key)",
    "comprehension": "[key for key in state_capitals]",
    "unpacking": "[*state_capitals]",
}

print("Python", platform.python_version())
for name, statement in methods.items():
    times = repeat(statement, globals=globals(), number=10_000, repeat=5)
    print(f"{name}: {min(times) / 10_000:.9f} seconds per conversion")

测得的时间取决于解释器、机器和字典大小,因此不存在固定的输出,也没有一种方法在所有情况下都最快。日常代码可优先使用清晰的 list(state_capitals);只有当转换确实带来明显开销时,才需要针对实际场景比较其他写法。