Подкласс dict: UserDict, dict или ABC? - PullRequest
39 голосов
/ 22 августа 2011

В чем разница между UserDict, dict и ABC и какой рекомендуется? Документы, кажется, устарели UserDict?

Также кажется, что UserDict update() будет использовать мой setitem метод, тогда как dict нет? Какие методы действительно необходимы для переопределения, если я хочу пользовательские функции setitem и getitem?

С ABC s я должен был бы реализовать абсолютно все методы, поскольку он не обеспечивает реализацию по умолчанию?

Я хочу сделать dict, который делает две вещи:

  • intern() все ключи и значения
  • сохранить некоторые значения в базе данных SQLite

Так какой из UserDict, dict и ABC лучше всего позволит мне это сделать?

Ответы [ 3 ]

45 голосов
/ 22 августа 2011

Если вам нужна пользовательская коллекция, которая фактически содержит данные, подкласс dict . Это особенно полезно, если вы хотите расширить интерфейс (например, добавить методы).

Ни один из встроенных методов не вызовет ваш пользовательский __getitem__ / __setitem__. Если вам нужен полный контроль над ними, создайте пользовательский класс, который реализует абстрактный базовый класс collections.MutableMapping.

ABC не предоставляет средства для хранения фактических данных, только интерфейс с реализациями по умолчанию для некоторых методов. Эти реализации по умолчанию, однако, будут вызывать ваши пользовательские __getitem__ и __setitem__. Вам придется использовать внутренний dict для хранения данных и реализовать все абстрактные методы: __len__, __iter__, __getitem__, __setitem__ и __delitem__.

Класс UserDict из модуля collections (в Python 2 этот модуль также называется UserDict) является оболочкой для внутреннего dict, реализующего MutableMapping ABC. Если вы хотите настроить поведение dict, эта реализация может стать отправной точкой.

В итоге:

  • MutableMapping определяет интерфейс. Подкласс это, чтобы создать что-то, что действует как dict. Это полностью зависит от вас, если и как вы храните данные.
  • UserDict - это реализация MutableMapping с использованием внутреннего "реального" dict в качестве хранилища. Если вы хотите, чтобы хранилище было похожим на dict, но перекрывало некоторые методы, предоставляемые dict, это может быть хорошей отправной точкой для вас. Но обязательно прочитайте код, чтобы узнать, как реализованы основные методы, чтобы вы были последовательны при переопределении метода.
  • dict - это "настоящая вещь". Подкласс это, если вы хотите расширить интерфейс. Переопределение методов для выполнения пользовательских действий может быть опасным, так как обычно существует несколько способов доступа к данным, и вы можете получить несовместимый API.
1 голос
/ 14 сентября 2018

По секретам Рецепты ниндзя Питона Книга

Единственная особенность, которую UserDict имеет помимо обычных операций со словарем, - это один атрибут:

данные: настоящий словарь для хранения содержимого класса UserDict

Чтобы добраться до элементов в словаре, вы должны либо перебрать их, либо вызвать items (). Хотя экземпляр UserDict поддерживает те же методы, представление, возвращаемое items (), заметно отличается:

  >>> from collections import UserDict
  >>> a = UserDict(a=1)
  >>> d = dict(d=3)  # regular dictionary for comparison

  >>> for k in d:
  ...     print(k, d[k])
  ... 
  d 3
  >>> d.items()
  dict_items([('d', 3)])
  >>> for k in a:
  ...     print(k, a[k])
  ... 
  a 1
  >>> a.items()
  ItemsView({'a': 1})

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

1 голос
/ 22 августа 2011

Не используйте UserDict класс - он вам не нужен.Как говорят в документах, вы можете просто подкласс dict напрямую.

Однако вам все еще нужен модуль UserDict для DictMixin:

Примечание: DictMixin, хотя официально не устарело, было удалено в Python 3, и рекомендуется в документах, которые вы используете collections.MutableMapping.Это, однако, имеет недостаток - вам нужно реализовать больше интерфейса словаря - __delitem__, __getitem__, __iter__, __len__ и __setitem__DictMixin вы можете просто реализовать те, которые хотите изменить, а остальные используют реализацию по умолчанию.

from UserDict import DictMixin

class MyDict(DictMixin, dict):
    def __setitem__(self, key, value):
        print key, value # just an example
        # use intern(key) or whatever here
        dict.__setitem__(self, key, value) # or
        # super(MyDict, self).__setitem__(key, value)

m = MyDict()

m['a'] = 'b'
# a b
m.update({'a': 'c'})
# a c

Она автоматически заставит update использовать __setitem__ так, как вы хотите.

...