Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 逻辑上合并物理上不同的词典_Python_Performance_Python 3.x - Fatal编程技术网

Python 逻辑上合并物理上不同的词典

Python 逻辑上合并物理上不同的词典,python,performance,python-3.x,Python,Performance,Python 3.x,我试着在两本字典周围写一个包装,这样它们看起来就像一本只供阅读的字典;写作应该引起例外 我这样做是为了节省内存,因为其他地方需要一本原始词典。我还认为,如果要查找组合词典中少于一半的元素,那么它比合并词典要快 以下是我的尝试: class LogicalMerge: def __init__(self, d1, d2): #d1 and d2 are dictionaries self.d1 = d1 self.d2 = d2 def __getitem__(se

我试着在两本字典周围写一个包装,这样它们看起来就像一本只供阅读的字典;写作应该引起例外

我这样做是为了节省内存,因为其他地方需要一本原始词典。我还认为,如果要查找组合词典中少于一半的元素,那么它比合并词典要快

以下是我的尝试:

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

这种方法是否存在任何设计、技术或性能问题?

您可以通过将u getitem uu改写为

这遵循了python的成语:请求原谅,而不是许可

我还认为这比合并字典要快

我强烈怀疑这一点,但你应该确定。您的方法引入了额外级别的间接寻址,并要求对密钥进行多次散列。这也必然会占用更多的内存

编辑:这里有另一种方法。用DictWithBackup替换一个dict,它的行为类似于dict,只是当一个键丢失时,它会查看另一个dict


此版本避免了异常处理。

出于性能原因,我更喜欢以下版本。“给定无”是一个永远不会有效发生的对象

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 _uu的对象来测试值相等o1==o2,或者——从性能角度看,更好的做法是——使用一个不可变的对象,即某个字符串错误_key _not _found _string,它不是每次新创建的。然后您甚至可以通过对象标识ido1==ido2进行比较,即使用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.updated2一样简单。如果d1是你在别处不用的字典,那么你可以用a。

这两个字典之间会有不对称吗?像一个比另一个长还是多用?或者像这样,最后一次使用的可能是将再次使用的?将在其他地方重复使用的是d2。d1除了在LogicalMerge中之外,在任何地方都不会使用,而且也只会使用一次。除此之外,我不能说哪个字典更大,访问它们的顺序等等。如果两个字典包含相同的键,我会在程序的前面知道,并引发一个异常。至于这样做的理由,我选择进行逻辑合并而不是物理合并以节省内存,而不是运行时。这两本词典都很大,其中一本d2必须保持不变。归根结底,问题是性能真的是一个问题吗?当然只有你能回答。如果不是,我更喜欢更清晰的代码。如果性能如此关键,他可以直接使用:v=self.d1.getk,self.d2.getk,None,然后是单个如果v为None:raise keyrork。如果代码稍微复杂一点,性能会更好。然而,内存的使用是绝对关键的。@moooeeep:嵌套的.get肯定不会有快捷方式行为。它不应该占用更多内存,try/except版本可能会慢一些:设置try/except块不是免费的,我敢打赌它比在一个字典中额外查找需要更多的资源。我强烈支持请求原谅,而不是许可,但如果正确,我认为try/except块在这种情况下会比if块慢很多。根据max的一条评论,d2中的每一项都不会出现在d1中,因此d2中的每一项都会出现例外。如果d2的尺寸与d1相当,则会有很多例外情况。我想这个习惯用法适用于异常很少的情况。@chrisn654:表示.setdefault查找可能比try/except慢。性能问题最好使用真实的输入数据和分析器来回答。@larsmans:哈希多次-这是一个很好的观点。但是,合并词典的内存成本太高,因此不可选择。我必须吃任何我必须花费的时间。
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
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