Логически объединяющие физически разные словари - PullRequest
0 голосов
/ 22 января 2012

Я пытаюсь написать обертку вокруг двух словарей, чтобы они выглядели как один словарь (только для чтения; запись должна вызывать исключения).

Я делаю это для экономии памяти, так как один из оригинальных словарей нужен где-то еще. Я также думаю, что это быстрее, чем объединение словарей, если будет найдено менее половины элементов в объединенных словарях.

Вот моя попытка:

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

Есть ли какие-либо проблемы с дизайном, техническими проблемами или производительностью при таком подходе?

Ответы [ 2 ]

4 голосов
/ 22 января 2012

Вы можете сэкономить один поиск на вызов, переписав __getitem__ как

try:
    return self.d1[x]
except KeyError:
    return self.d2[x]

. Это следует за пионической идиомой «просить прощения, а не разрешения».также думаю, что это быстрее, чем объединение словарей

Я сильно сомневаюсь в этом, но вы должны измерить, чтобы быть уверенным.Ваш подход вводит дополнительный уровень косвенности и требует многократного хеширования ключа.Это также обязательно займет больше памяти.

Редактировать : вот альтернативный подход.Замените один из ваших диктов на DictWithBackup, который ведет себя как dict, за исключением того, что когда ключ отсутствует, он смотрит на другой dict.

class DictWithBackup(dict):
    def __init__(self, backup):
         self._backup = backup

    def __missing__(self, key):
         return self._backup[key]

В этих версиях исключена обработка исключений.

3 голосов
/ 22 января 2012

По соображениям производительности я бы предпочел следующее.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * None 1004 * * * * * * * * * *

*.Обратите внимание, что вам либо нужен объект, который реализует __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 ).

...