【发布时间】:2021-07-09 06:08:48
【问题描述】:
我正在尝试实现一个 context manager class 来处理字典上的 KeyError。
想一想:
bikes = ['Honda', 'Yamaha', 'Kawasaki', 'Suzuki']
colors = ['Red', 'Blue', 'Green', 'White', 'Black']
有了这两个列表,我必须构建一个包含每个品牌和颜色的销售额的两层词典,例如:
bike_sales_by_color = {
'Honda': {
'Red': 100,
'Blue': 125,
},
'Yamaha': {
'Black': 50,
'White': 60,
},
# etc...
}
(在本例中,将销售额视为随机数)。
我解决这个问题的实现是最普通/常规的:
def get_bikes_sales():
bikes_sales = {}
for bike in bikes: # iterate over two lists
for color in colors:
try: # try to assign a value to the second-level dict.
bikes_sales[bike][color] = 100 # random sales int value
except KeyError: # handle key error if bike is not yet in the first-level dict.
bikes_sales[bike] = {}
bikes_sales[bike][color] = 100 # random sales int value
return bikes_sales
上面函数的行为是预期的,但是我想要一个用户定义的类来拯救我们每次不得不面对这个问题时重复这段代码,我认为一个上下文管理器类将是实现的方式它。
这就是我所做的,但它没有按预期工作:
class DynamicDict:
"""
Context manager class that immediately creates a new key with the intended value
and an empty dict as the new created key's value if KeyError is raised.
Useful when trying to build two or more level dictionaries.
"""
def __init__(self):
self.dictionary = {}
def __enter__(self):
return self.dictionary
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is KeyError:
self.dictionary[exc_val.args[0]] = {}
return True
这样我们就可以制作类似的东西:
with DynamicDict() as bikes_sales:
for bike in bikes:
for color in colors:
bikes_sales[bike][color] = 100
但是 with 块内的迭代在上下文管理器处理的第一个 KeyError 之后停止,我得到的结果只有这个:{'Honda': {}}
【问题讨论】:
-
你考虑过使用默认字典吗?您将拥有
bike_sales = defaultdict(dict),然后是 for 循环,并且不需要上下文管理器。
标签: python python-3.x exception with-statement keyerror