字典
列表让你通过位置查找内容。但很多时候你希望通过名称查找。不是"给我第 3 项",而是"给我小明的分数"。字典将数据存储为键值对:你通过键来查找值,而不是位置。
创建字典
花括号,每个键和值之间用冒号分隔,键值对之间用逗号分隔。键几乎总是字符串。值可以是任何东西:数字、字符串、其他列表,甚至其他字典。
player = {
"name": "小明",
"score": 87,
"level": 5,
"alive": True,
}访问值
使用方括号加键来获取值。如果键不存在,Python 会抛出 KeyError。当你不确定键是否存在时,使用 .get():它返回 None 而不是崩溃,或者你指定的默认值。
player = {"name": "小明", "score": 87}
player["name"] # "小明"
player["score"] # 87
player["lives"] # KeyError (key doesn't exist)player.get("score") # 87
player.get("lives") # None (no error, returns None by default)
player.get("lives", 3) # 3 (use this default if key is absent)每当键可能缺失时,.get() 更安全:
count = inventory.get("arrows", 0) # 0 if "arrows" isn't in the dict添加和更新
用方括号给键赋值。如果键已存在,值被替换。如果还不存在,则创建一个新条目。使用 .update() 一次性合并整个其他字典。
player = {"name": "小明", "score": 87}
player["score"] = 92 # update existing
player["level"] = 5 # add new keyextras = {"level": 5, "alive": True}
player.update(extras) # adds/overwrites with keys from extras移除项
有四种方式可以移除条目。.pop() 移除一个键并把值返回给你。带默认值的 .pop() 在键可能不存在时是安全的。del 移除一个键且没有返回值。.clear() 清空整个字典。
player = {"name": "小明", "score": 87, "level": 5}
player.pop("level") # removes "level" and returns 5
player.pop("lives", None) # safe pop, returns None if key absent
del player["score"] # removes "score", no return value
player.clear() # removes everything带默认值的 .pop() 是移除一个可能不存在的键的最安全方式。
遍历
三种视图让你能遍历字典的不同部分。仅遍历字典会给你键。.values() 给值。.items() 同时给出两者,这是你最常用的:将每对解包到两个名字中,以获得简洁、易读的循环。
player = {"name": "小明", "score": 87, "level": 5}
for key in player: # iterate keys (most common)
print(key)
for key in player.keys(): # same, explicit keys view
print(key)
for value in player.values(): # just the values
print(value)
for key, value in player.items(): # both, most useful
print(f"{key}: {value}").items() 是你最常用的。将每对解包到两个名字中使循环可读性强。
检查成员
in 检查键是否存在于字典中。它不检查值,只检查键。要检查某项是否不存在,使用 not in。
player = {"name": "小明", "score": 87}
"name" in player # True
"lives" in player # False
"lives" not in player # Truein 只检查键。要检查值,使用 in player.values(),虽然这种情况很少需要。
嵌套字典
值本身也可以是字典。这就是你如何表示多层级结构化数据:一个有 stats 部分的玩家,一个有子部分的配置文件。两组方括号访问嵌套值:第一个选择外层键,第二个选择内层键。
users = {
"小明": {"score": 87, "level": 5},
"小红": {"score": 74, "level": 3},
}
users["小明"]["score"] # 87
users["小红"]["level"] # 3用链式方括号访问。对于深度嵌套结构,这可能变得笨重,所以尽可能保持嵌套浅。
setdefault
.setdefault() 如果键存在则读取它,如果不存在则将其设置为默认值,然后返回该值。当你需要一个键存在但又不想在它已经存在时覆盖它时,这很有用。
inventory = {}
inventory.setdefault("arrows", 0) # sets "arrows": 0, returns 0
inventory.setdefault("arrows", 10) # "arrows" already exists, no change, returns 0它对于构建分组结构而无需先检查键是否存在很有用:
groups = {}
for name, team in players:
groups.setdefault(team, []).append(name)collections.defaultdict 和 Counter
标准库有两个 dict 子类,可以自动处理常见模式。defaultdict 为缺失的键创建一个默认值,所以你永远不会得到 KeyError。Counter 计算序列中每项出现的频率,并以字典形式给你结果。
collections 导入
defaultdict 和 Counter 需要从标准库导入。导入将在模块章节中介绍。
from collections import defaultdict
groups = defaultdict(list)
for name, team in players:
groups[team].append(name) # no KeyError if team is newfrom collections import Counter
words = ["cat", "dog", "cat", "bird", "cat", "dog"]
counts = Counter(words)
# Counter({'cat': 3, 'dog': 2, 'bird': 1})
counts.most_common(2) # [('cat', 3), ('dog', 2)]Counter 节省了大量"在循环中计数"的样板代码。
实战
构建一个分数追踪器并打印包含所有条目的摘要:
scores = {"小明": 87, "小红": 74, "小华": 92, "小刚": 55}
total = sum(scores.values())
average = total / len(scores)
print(f"Players: {len(scores)}")
print(f"Average: {average:.1f}")
print(f"Highest: {max(scores.values())}")
print(f"Lowest: {min(scores.values())}")
print()
for name, score in scores.items():
print(f" {name}: {score}")
