Как “отлично” переопределить dict?

Как я могу сделать максимально "идеальный" подкласс dict? Конечная цель должна иметь простой dict, в котором ключи являются нижним регистром.

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

  • Если я переопределяю __getitem__/__setitem__, затем get/set не работать. Как я могу заставить их работать? Конечно, я не должен реализовывать их индивидуально?

  • Я препятствую тому, чтобы соление работало, и я должен реализовать __setstate__ и т.д.?

  • Сделайте мне нужно repr, update и __init__?

  • Если я просто использую mutablemapping (кажется, что не нужно использовать UserDict или DictMixin)? Если так, как? Документы не точно поучительны.

Вот мое первое движение в нем, get() не работает и несомненно существует много других незначительных проблем:

class arbitrary_dict(dict):
    """A dictionary that applies an arbitrary key-altering function
       before accessing the keys."""

    def __keytransform__(self, key):
        return key

    # Overridden methods. List from 
    # https://stackoverflow.com/questions/2390827/how-to-properly-subclass-dict

    def __init__(self, *args, **kwargs):
        self.update(*args, **kwargs)

    # Note: I'm using dict directly, since super(dict, self) doesn't work.
    # I'm not sure why, perhaps dict is not a new-style class.

    def __getitem__(self, key):
        return dict.__getitem__(self, self.__keytransform__(key))

    def __setitem__(self, key, value):
        return dict.__setitem__(self, self.__keytransform__(key), value)

    def __delitem__(self, key):
        return dict.__delitem__(self, self.__keytransform__(key))

    def __contains__(self, key):
        return dict.__contains__(self, self.__keytransform__(key))


class lcdict(arbitrary_dict):
    def __keytransform__(self, key):
        return str(key).lower()

203
задан Bonifacio2 28 January 2018 в 04:23
поделиться

1 ответ

Вы можете легко написать объект, который ведет себя как dict, с помощью ABC s (Абстрактные базовые классы) из модуля collections . Это даже говорит вам если вы пропустили метод, то ниже представлена ​​минимальная версия, которая закрывает ABC.

import collections


class TransformedDict(collections.MutableMapping):
    """A dictionary that applies an arbitrary key-altering
       function before accessing the keys"""

    def __init__(self, *args, **kwargs):
        self.store = dict()
        self.update(dict(*args, **kwargs))  # use the free update to set keys

    def __getitem__(self, key):
        return self.store[self.__keytransform__(key)]

    def __setitem__(self, key, value):
        self.store[self.__keytransform__(key)] = value

    def __delitem__(self, key):
        del self.store[self.__keytransform__(key)]

    def __iter__(self):
        return iter(self.store)

    def __len__(self):
        return len(self.store)

    def __keytransform__(self, key):
        return key

Вы получаете несколько бесплатных методов из ABC:

class MyTransformedDict(TransformedDict):

    def __keytransform__(self, key):
        return key.lower()


s = MyTransformedDict([('Test', 'test')])

assert s.get('TEST') is s['test']   # free get
assert 'TeSt' in s                  # free __contains__
                                    # free setdefault, __eq__, and so on

import pickle
assert pickle.loads(pickle.dumps(s)) == s
                                    # works too since we just use a normal dict

Я бы не стал подклассом dict (или других встроенных функций) напрямую. Часто это не имеет смысла, потому что на самом деле вы хотите реализовать интерфейс dict . И это именно то, для чего нужны азбуки.

214
ответ дан 23 November 2019 в 04:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: