Subclassing dict: должен ли вызывать .__ init __ ()?

Вот двоякий вопрос с теоретической частью и практический:

Когда подклассификация dict:

  • Почему автоматические методы __init__ класса Python не запускаются автоматически?
  • Python: Как работает наследование __slots__ в подклассах?
  • подклассы объекта pandas работают иначе, чем подкласс другого объекта?
  • Как вы используете синтаксис разрезания многоточия в Python?
  • Проблема с подклассом numpy ndarray
  • class ImageDB(dict): def __init__(self, directory): dict.__init__(self) # Necessary?? ... 

    должен был бы вызывать dict.__init__(self) , как мера «безопасности» (например, если есть некоторые нетривиальные детали реализации, которые имеют значение)? есть ли риск того, что код сломается с будущей версией Python, если dict.__init__() не вызывается? Я ищу фундаментальную причину делать то или другое, здесь (практически, вызов dict.__init__() безопасен).

    Я предполагаю, что когда ImageDB.__init__(self, directory) , self уже является новым пустым объектом dict, и поэтому нет необходимости вызывать dict.__init__ (я хочу, чтобы dict был пустым, сначала) , Это верно?

    Изменить :

    Более практический вопрос, стоящий за основным вопросом выше, заключается в следующем. Я думал о подклассе dict, потому что я часто использовал синтаксис db […] (вместо того, чтобы делать db.contents […] все время); единственные данные (атрибут) объекта действительно действительно являются dict. Я хочу добавить несколько методов в базу данных (например, get_image_by_name() или get_image_by_code() , например) и только переопределить __init__() , потому что база данных изображений определяется каталогом, которая ее содержит.

    Таким образом , вопрос (практический) может быть: что является хорошей реализацией для того, что ведет себя как словарь, за исключением того, что его инициализация отличается (она принимает только имя каталога) и что она имеет дополнительные методы?

    Во многих ответах упоминались «Заводы». Поэтому я предполагаю, что все это сводится к: вы подклассифицируете dict, переопределяете __init__() и добавляете методы, или вы пишете (фабричную) функцию, которая возвращает dict, к которой вы добавляете методы? Я склонен предпочитать первое решение, потому что фабричная функция возвращает объект, тип которого не указывает, что он имеет дополнительные семантики и методы, но что вы думаете?

    Изменить 2 :

    Из каждого ответа я понимаю, что подклассировать не рекомендуется, когда новый класс «не является словарем», и в частности, когда его метод __init__ не может принимать те же аргументы, что и dict __init__ (что имеет место в «практическом вопрос "выше). Другими словами, если я правильно понимаю, консенсус представляется следующим: когда вы подклассом, все методы (включая инициализацию) должны иметь одинаковую подпись, как методы базового класса. Это позволяет isinstance (subclass_instance, dict) гарантировать, что subclass_instance.__init__() может использоваться, например, как dict.__init__() .

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

  • Преобразование строки в dict?
  • python dict: get vs setdefault
  • Замена строк со словарем, осложнения с пунктуацией
  • Сортировка словаря и запись его в файл CSV
  • Группируйте и суммируйте значения списка словарей в Python
  • Почему это определение словаря вызывает синтаксическую ошибку?
  • 4 Solutions collect form web for “Subclassing dict: должен ли вызывать .__ init __ ()?”

    Вероятно, вы должны назвать dict.__init__(self) при подклассификации; на самом деле, вы не знаете, что происходит именно в dict (поскольку оно встроено), и это может различаться в разных версиях и реализациях. Не вызывать это может привести к неправильному поведению, поскольку вы не можете знать, где dict держит свои внутренние структуры данных.

    Кстати, вы не сказали нам, что вы хотите делать; если вам нужен класс с поведением dict (mapping), и вам действительно не нужен dict (например, нет кода, делающего isinstance(x, dict) любом месте вашего программного обеспечения, как и должно быть), вам, вероятно, лучше при использовании UserDict.UserDict или UserDict.DictMixin если вы находитесь на python <= 2.5 или collections.MutableMapping UserDict.DictMixin , если вы находитесь на python> = 2.6. Это предоставит вашему классу отличное поведение диктата.

    EDIT: Я прочитал в другом комментарии, что вы не переопределяете какой-либо метод dict'а! Тогда нет никакого смысла в подклассе вообще, не делайте этого.

     def createImageDb(directory): d = {} # do something to fill in the dict return d 

    EDIT 2: вы хотите наследовать от dict, чтобы добавлять новые методы, но вам не нужно переопределять их. Чем может быть хороший выбор:

     class MyContainer(dict): def newmethod1(self, args): pass def newmethod2(self, args2): pass def createImageDb(directory): d = MyContainer() # fill the container return d 

    Кстати: какие методы вы добавляете? Вы уверены, что создали хорошую абстракцию? Возможно, вам лучше использовать класс, который определяет методы, которые вам нужны, и использовать внутри него «нормальный» файл.

    Factory func: http://en.wikipedia.org/wiki/Factory_method_pattern

    Это просто способ делегирования конструкции экземпляра функции вместо переопределения / изменения ее конструкторов.

    Обычно вы должны называть базовый класс __init__ так зачем делать исключение здесь?

    Либо не переопределяйте __init__ либо если вам нужно переопределить __init__ вызов базового класса __init__ , Если вы беспокоитесь о аргументах, просто передайте * args, ** kwargs или ничего, если вы хотите, чтобы пустой dict, например

     class MyDict(dict): def __init__(self, *args, **kwargs ): myparam = kwargs.pop('myparam', '') dict.__init__(self, *args, **kwargs ) 

    Мы не должны предполагать, что baseclass делает или не делает, неправильно не называть базовый класс __init__

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

     class Dotdict( dict ): """ d.key == d["key"] """ def __init__(self, *args, **kwargs): dict.__init__( self, *args, **kwargs ) self.__dict__ = self def __getnewargs__(self): # for cPickle.dump( d, file, protocol=-1) return tuple(self) 

    PEP 372 имеет дело с добавлением упорядоченного dict в модуль коллекций.

    Он предупреждает, что «подклассификация dict – это нетривиальная задача, и многие реализации не переопределяют все методы, которые могут привести к неожиданным результатам».

    В предлагаемом (и принятом) патче к python3.1 используется __init__ который выглядит так:

     +class OrderedDict(dict, MutableMapping): + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + if not hasattr(self, '_keys'): + self._keys = [] + self.update(*args, **kwds) 

    Исходя из этого, он выглядит как dict.__init__() не нужно вызывать.

    Редактировать: Если вы не переопределяете или не применяете какие-либо методы dict , то я согласен с Аланом Францони: используйте фабрику dict, а не подклассификацию:

     def makeImageDB(*args,**kwargs): d = {} # modify d return d 
    Python - лучший язык программирования в мире.