Python: наследование или состав

Скажем, что у меня есть class, который использует некоторые функции dict. Я использовал для компоновки объекта dict внутри и предоставлял некоторый доступ извне, но недавно думал о просто наследовании dict и добавлении некоторых атрибутов и методов, которые могут потребоваться. Это хороший способ пойти, или я должен придерживаться композиции?

Ответы

Ответ 1

Наследование очень часто злоупотребляют. Если ваш класс не предназначен для использования в качестве универсального словаря с дополнительной функциональностью, я бы сказал, что композиция - это способ пойти.

Сохранение переадресации вызовов обычно не является достаточной причиной для выбора наследования.

Из книги Pattern Design:

Использовать композицию объекта над наследованием класса

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

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

Весь текст здесь: http://blog.platinumsolutions.com/node/129

Ответ 2

Оба хороши, но я бы предпочел наследовать, поскольку это будет означать меньше кода (который всегда хорош до тех пор, пока он доступен для чтения).

Погружение в Python имеет очень важный пример.

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

class FileInfo(dict):                  
   "store file metadata"
   def __init__(self, filename=None): 
       self["name"] = filename
  • Первое отличие состоит в том, что вам не нужно импортировать модуль UserDict, поскольку dict является встроенным типом данных и всегда доступен. Во-вторых, вы наследуете непосредственно от dict, а не от UserDict.UserDict.
  • Третье отличие - тонкое, но важное. Из-за того, как UserDict работает внутри, он требует, чтобы вы вручную вызвали его метод __init__ для правильной инициализации своих внутренних структур данных. dict не работает так; это не оболочка, а не требует явной инициализации.

Ответ 3

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

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

Ответ 4

Должно ли isinstance(my_object, dict) вернуть True или False? Другими словами, если вы случайно передаете один из объектов чему-то, что хочет dict, следует ли его беспечно попытаться использовать его как dict? Наверное, нет, поэтому используйте композицию.