按名字查找值
字典(dict)把键映射到值:{"AAPL": 184.5, "MSFT": 410.2}。列表按位置找元素,字典按键找元素,而且无论有多少条目,查找都很快。prices["AAPL"] 读取一个值,prices["TSLA"] = 251.0 添加新条目或替换已有的,"AAPL" in prices 询问某个键是否存在。用方括号读取不存在的键会引发 KeyError。
prices = {"AAPL": 184.5, "MSFT": 410.2}
# Read, add and replace
print(prices["AAPL"]) # 184.5
prices["TSLA"] = 251.0
prices["AAPL"] = 185.0
print(prices) # {'AAPL': 185.0, 'MSFT': 410.2, 'TSLA': 251.0}
# in tests the keys; a missing key raises KeyError
print("MSFT" in prices, "GOOG" in prices) # True False
try:
prices["GOOG"]
except KeyError as error:
print("no such key:", error)get:键不存在并不算错误
prices.get("GOOG", 0.0) 返回对应的值;键不存在时返回你给的默认值(没给则为 None),并且从不报错。这让计数很容易:counts[symbol] = counts.get(symbol, 0) + 1 对新代码从 0 开始,每出现一次加一。当缺键是你想知道的错误时用 [],当缺键属于正常情况时用 get。
# get() with a default never raises
prices = {"AAPL": 184.5}
print(prices.get("AAPL", 0.0)) # 184.5
print(prices.get("GOOG", 0.0)) # 0.0
print(prices.get("GOOG")) # None
# Counting with get
counts = {}
for symbol in ["AAPL", "MSFT", "AAPL", "AAPL"]:
counts[symbol] = counts.get(symbol, 0) + 1
print(counts) # {'AAPL': 3, 'MSFT': 1}遍历字典
单独的 for key in prices 遍历的是键。用 prices.values() 取值,用 prices.items() 取 (键, 值) 对,并在循环里解包:for symbol, price in prices.items()。字典会记住键被添加的顺序。遍历同一个字典时不要增删键;遍历它的副本或构建一个新字典。
# keys(), values() and items()
positions = {"AAPL": 200, "MSFT": 50, "GOOG": 0}
prices = {"AAPL": 184.5, "MSFT": 410.2}
for symbol in positions:
print(symbol, end=" ") # AAPL MSFT GOOG
print()
total = 0.0
for symbol, quantity in positions.items():
total += quantity * prices.get(symbol, 0.0)
print(round(total, 2)) # 57410.0删除、合并与复制
prices.pop("AAPL", None) 删除一个键并返回其值(键不存在时返回默认值);del prices["AAPL"] 删除它,键不存在时引发 KeyError。a.update(b) 把 b 的条目复制进 a,会改变 a;{**a, **b} 或 a | b 构建新字典,共有的键以 b 为准。和列表一样,copy = prices 只是多了一个名字:真正的拷贝请用 dict(prices) 或 prices.copy()。
# Removing and merging
book = {"AAPL": 200, "MSFT": 50}
sold = book.pop("MSFT", 0)
print(sold, book) # 50 {'AAPL': 200}
# {**a, **b} builds a new dict; b wins on shared keys
defaults = {"fee": 0.001, "currency": "USD"}
custom = {"fee": 0.0005}
settings = {**defaults, **custom}
print(settings) # {'fee': 0.0005, 'currency': 'USD'}
print(defaults) # unchanged: {'fee': 0.001, 'currency': 'USD'}什么可以作键
键必须是可哈希的,实际上就是不能被修改:字符串、数字及由它们组成的元组可以,列表和字典不行。元组适合做复合键,比如 (symbol, venue)。值可以是任何东西,包括另一个列表或字典。同一个键只能出现一次,再次赋值会替换旧值。
# A tuple as a compound key, a list as a value
best = {("AAPL", "NYSE"): 184.6, ("AAPL", "ARCA"): 184.5}
print(best[("AAPL", "ARCA")]) # 184.5
fills = {"AAPL": [100, 250], "MSFT": [75]}
fills["AAPL"].append(40)
print(fills) # {'AAPL': [100, 250, 40], 'MSFT': [75]}
# A list cannot be a key
try:
{["AAPL"]: 1}
except TypeError as error:
print("not hashable:", error)prices[symbol] 的意思是“这个键必须存在”,不存在就明确报错;prices.get(symbol, default) 的意思是“不存在也没关系”。用默认值掩盖真正的错误,与在正常情况下崩溃同样糟糕,所以要想清楚自己的意图。实验还会检查你收到的字典是否保持不变。d[key]、d[key] = value、key in d:读取、写入、检测键。d.get(key, default):安全查找;d.items():用于遍历的键值对。d.pop(key, default)、del d[key]、d.update(other)、{**a, **b}:删除与合并。
下一节:集合,由唯一值组成的集合,成员检测很快,集合运算也很简洁。
实验:评分内容
- 用
latest_prices为每个代码保留最新价格25 分 - 用
count_symbols统计每个代码出现的次数25 分 - 用
portfolio_value根据两个字典计算投资组合价值25 分 - 用
merge_positions合并两份持仓账本25 分