Что следует учитывать перед списком подклассов?
Недавно я перешел к проблеме кодирования, которую я имел, и кто-то, просматривая код, сказал, что список подклассов был плохим (моя проблема не была связана с этим классом). Он сказал, что вы не должны этого делать, и что он пришел с кучей плохих побочных эффектов. Это правда?
Я прошу, если список обычно плохо подходит для подкласса, и если да, то в чем причины. В качестве альтернативы, что я должен рассмотреть перед списком подклассов в Python?
Ответы
Ответ 1
Нет преимуществ для подклассов list
. Ни один из методов не будет использовать какие-либо методы, которые вы переопределите, так что вы можете иметь неожиданные ошибки. Кроме того, очень часто сбивать с толку делать такие вещи, как self.append
вместо self.foos.append
или особенно self[4]
, а не self.foos[4]
для доступа к вашим данным. Вы можете сделать что-то, что работает точно как список или (лучше), но очень похожий на список, который вам действительно нужен, просто подклассифицируя object
.
Ответ 2
абстрактные базовые классы, представленные в collections
, особенно MutableSequence
, могут быть полезны при реализации классов, подобных спискам. Они доступны в Python 2.6 и более поздних версиях.
С ABC вы можете реализовать "базовые" функциональные возможности своего класса и предоставить методы, логически зависящие от того, что вы определили.
Например, реализовать __getitem__
в классе collections.Sequence
-derived будет достаточно, чтобы предоставить вашему классу __contains__
, __iter__
и другие методы.
Вы все равно можете использовать объект списка, который будет использоваться для тяжелого подъема.
Ответ 3
Я думаю, что первый вопрос, который я задал себе, это: "Является ли мой новый объект действительно списком?". Он идет, как список, говорит, как список? Или это что-то еще?
Если это список, то все стандартные методы списка должны иметь смысл.
Если стандартные методы списка не имеют смысла, то ваш объект должен содержать список, а не список.
В предыдущем списке подклассификаций python (2.2?) была плохая идея по различным техническим причинам, но в современном python это нормально.
Ответ 4
Ник прав.
Кроме того, хотя я не могу говорить с Python, в других языках OO (Java, Smalltalk) подклассификация списка - плохая идея. Вместо этого следует избегать наследования в целом и использовать состав делегаций.
Скорее, вы создаете контейнерный класс и делегируете вызовы в список. Класс контейнера имеет ссылку на список, и вы можете даже разоблачить вызовы и возвраты списка в своих собственных методах.
Это добавляет гибкости и позволяет вам изменить реализацию (другой тип списка или структуру данных) позже без нарушения какого-либо кода. Если вы хотите, чтобы ваш список выполнял разные вещи типа listy, ваш контейнер может это сделать и использовать простой список как простую структуру данных.
Представьте, если у вас было 47 различных видов использования списков. Вы действительно хотите поддерживать 47 различных подклассов?
Вместо этого вы можете сделать это через контейнер и интерфейсы. Один класс для поддержки и позволяет людям называть ваши новые и улучшенные методы с помощью интерфейса (интерфейсов), при этом реализация остается скрытой.