Рекомендации по определению класса, подобного dict: должен ли он наследовать от dict() или иметь dict в качестве атрибута?

#python #dictionary

Вопрос:

Я намерен определить класс со свойствами, указанными здесь ниже, и мне интересно, каков наилучший подход между тем, чтобы сделать его наследуемым dict или dict иметь атрибут has?

Цель занятия

Это класс, подобный dict, экземпляр которого будет отслеживать файлы на диске, т. Е. он управляет сопоставлением между ключом и дескриптором набора данных (это не прямой файл — для полноты, это ParquetFile() экземпляр из fastparquet библиотеки). Называя этот класс DataStore() , мой вопрос затем материализуется в том, какой наилучший подход между:

 # Defining the indexer class 1st @dataclass class Indexer:  country: str  city: str   @property  def to_path(self):  # Method to derive a path from an Indexer instance  @classmethod  def from_path(cls, path):  # Method to derive a new Indexer instance from a path.  # Approach 1: dict as attribute class DataStore1:  def __init__(self, path:str, indexer: Indexer):  # path: path of main directory, containing several parquet datasets  # indexer: class used generate a key from path of individual parquet dataset.  self.data = self._keys_datasets_from_path(path, indexer)  self.basepath = path   def _keys_datasets_from_path(self, path:str, indexer: Indexer) -gt; dict()  # Stuff with scanfile(path) and so on...  # Approach 2: inheriting from dict class DataStore2(dict):  def __init__(self, path:str, indexer: Indexer):  # path: path of main directory, containing several parquet datasets  # indexer: class used generate a key from path of individual parquet dataset.  super.__init__(self._keys_datasets_from_path(path, indexer))  self.basepath = path   def _keys_datasets_from_path(self, path:str, indexer: Indexer) -gt; dict()  # Stuff with scanfile(path) and so on...  

Требования

  • Имеет определенный атрибут:
    • basepath
  • Примите один тип ключа (в примере выше: Indexer ).
    • проверьте тип ключа при добавлении или изменении нового значения, создайте исключение, если оно не указанного типа.
  • Итерация по ключам (как стандартная dict ) for key in my_store:

Синктатический сахар

  • При установке значения для ключа поведение отличается в зависимости от типа значения:
    • если значение является ParquetFile() экземпляром, то используется нормальное поведение dict. my_store[my_new_key] = my_parquet_file_obj
    • если значение является кортежем (dict, DataFrame)
      • если ключ новый, то фрейм данных-это данные, используемые для создания ParquetFile() экземпляра, а дикт-конфигурация, используемая для записи набора данных. my_store[my_new_key] = (config_for_writing_new_dataset, data_to_write)
      • если ключ существует, фрейм данных-это данные для добавления, а дикт-конфигурация, используемая для добавления данных. my_store[my_existing_key] = (config_for_appending, data_to_append)

Итак, учитывая эти требования, каков был бы наилучший подход? Может быть, вопрос сводится к тому, какой подход является наиболее гибким для достижения заданных требований и целевого синтаксического сахара? Заранее спасибо за любую помощь и советы!

Комментарии:

1. Есть ли у них какие-либо различия в ваших двух подходах? Как я знаю, второй метод делает наследование классов object lt;- dict lt;- target вместо object lt;- target первого, поэтому я бы предложил использовать первые подходы, не нужно усложнять ситуацию. Или у вас есть особые потребности..

2. Спасибо, что попытались помочь! Извините, я не понимаю, что такое » они » в «Есть ли у них какие-либо различия»? Также я не понимаю, что такое «цель» в цепочке, которую вы сравниваете? Цепочка, которую я вижу между 1 и 2: наследование: dict -gt; DataStore -gt; obj / атрибут: DataStore -gt; obj -gt; dict obj но не уверен, как ее интерпретировать.

3. Не делай этого. В итоге вы получите код, который выглядит как обычные операции диктовки, но ведет себя совсем по-другому. Это поле деятельности для любого разработчика , который появится позже (включая вас через 6 месяцев). Используйте пользовательский класс с соответствующими именами методов. Или, если это не ваша сумка, храните вещи в обычном диктанте и манипулируйте ими с помощью обычных функций, которые понимают логику домена.

4. @pierre_j: Вы рассматривали возможность наследования от collections.abc.MutableMapping , который предназначен для создания пользовательских dict вещей? Это в основном обертывание dict случая члена, но вам нужно только определить __getitem__ , __setitem__ , __delitem__ , __iter__ , и __len__ , и ABC предоставляет все остальные dict методы для вас.

5. @pierre_j: Нет проблем. Просто для ясности вам также необходимо указать a __init__ (именно там вы можете решить, где вы будете хранить внутреннюю dict информацию ). Это прямо не указано в документах, но вы тоже несете за это ответственность.