我正在尝试围绕两个字典编写一个包装器,这样它们看起来像一个字典(仅用于阅读;写入应该引发异常)。
我这样做是为了节省内存,因为其他地方需要一个原始字典。我认为它比合并字典更快,如果组合字典中的元素不到一半将会被查找。
这是我的尝试:
class LogicalMerge:
def __init__(self, d1, d2):
#d1 and d2 are dictionaries
self.d1 = d1
self.d2 = d2
def __getitem__(self, x):
if x in self.d1:
return self.d1[x]
else:
return self.d2[x]
d1 = {1:2, 3:4}
d2 = {5:10}
d = LogicalMerge(d1, d2)
d[1] # == 2
d[5] # == 10
此方法是否存在任何设计,技术或性能问题?
答案 0 :(得分:4)
通过将__getitem__
重写为
try:
return self.d1[x]
except KeyError:
return self.d2[x]
这遵循了"请求宽恕,而不是许可"的pythonic成语。
我也认为它比合并词典更快
我强烈怀疑,但你应该确定。您的方法引入了额外的间接级别,并且需要对密钥进行多次哈希处理。它也必然需要更多的记忆。
修改:这是另一种方法。使用DictWithBackup
替换您的某个词组,其行为类似于dict
,但是当缺少某个键时,它会查看另一个dict
。
class DictWithBackup(dict):
def __init__(self, backup):
self._backup = backup
def __missing__(self, key):
return self._backup[key]
此版本可避免异常处理。
答案 1 :(得分:3)
出于性能原因,我更喜欢以下内容。给定None
是一个永远不会有效发生的对象。
def __getitem__(self, k):
v = self.d1.get(k, None)
if v is None:
v = self.d2[k] # if you're going to raise an error anyway ...
return v
否则您可以默认获取自定义对象。注意,您需要一个实现__eq__
的对象来测试值相等(o1 == o2
),或者---更好的性能---您使用不可变对象,即某个字符串"error_key_not_found_string"
,每次都不是新创建的。然后,您甚至可以按对象标识id(o1) == id(o2)
进行比较,即使用is
运算符。 (您不需要提供__eq__
。)
def __getitem__(self, k):
v = self.d1.get(k, "error_key_not_found_string")
# if id(v) == id("error_key_not_found_string":
if v is "error_key_not_found_string":
v = self.d2[k] # if you're going to raise an error anyway ...
return v
你有没有想过这个案例,这个项目在两个字典中?
总之,从设计角度来看,我觉得这有点令人困惑。性能增益是否真的证明了额外的错误和混淆源?另外,您将失去所有其他dict
功能......
这可以像d1.update(d2)
一样简单。鉴于d1
是您不在其他地方使用的字典(您可以使用deepcopy)。