Кажется, есть две причины, по которым класс может быть "окончательным" в Python.
1. Нарушение инварианта класса
Классы, которые следуют шаблону Singleton, имеют инвариант, заключающийся в том, что существует ограниченное (заранее определенное) количество экземпляров. Любое нарушение этого инварианта в подклассе будет несовместимо с целью класса и не будет работать правильно. Примеры:
bool
: True
, False
; см. комментарии Гвидо
NoneType
: None
NotImplementedType
: NotImplemented
ellipsis
: Ellipsis
В этой категории могут быть случаи, отличные от шаблона Singleton, но мне ничего не известно.
2. Нет убедительного варианта использования
Класс, реализованный на C, требует дополнительной работы, чтобы разрешить создание подклассов (по крайней мере, в CPython). Выполнение такой работы без убедительного варианта использования не очень привлекательно, поэтому вероятность того, что добровольцы заявятся, меньше. Примеры:
Примечание 1:
Первоначально я думал, что есть допустимые варианты использования, но просто недостаточный интерес к подклассам function
и operator.itemgetter
. Спасибо @agf за указание на предлагаемые варианты использования здесь и здесь неубедительны (см. agf комментарии к вопросу).
Заметка 2:
Меня беспокоит то, что другая реализация Python может случайно разрешить создание подкласса для класса final в CPython. Это может привести к непереносимости кода (вариант использования может быть слабым, но кто-то все равно может написать код, который является подклассом function
, если его Python поддерживает это). Это можно решить, пометив в документации Python все встроенные и стандартные библиотечные классы, которые не могут быть подклассами, и потребовав, чтобы все реализации следовали поведению CPython в этом отношении.
Заметка 3:
Сообщение, создаваемое CPython во всех вышеперечисленных случаях:
TypeError: type 'bool' is not an acceptable base type
Это довольно загадочно, как показывают многочисленные вопросы на эту тему. Я внесу предложение добавить в документацию абзац, объясняющий окончательные классы, и, возможно, даже изменить сообщение об ошибке на:
TypeError: type 'bool' is final (non-extensible)
person
max
schedule
11.04.2012
NoneType
— еще один пример. - person Duncan   schedule 08.04.2012function
, и теперь ему нужно провести рефакторинг кода, чтобы избежать этого наследования). - person max   schedule 10.04.2012NotImplementedType
(т. е.type(NotImplemented)
) иellipsis
(т. е.type(...)
) — еще два примера. Как и в случае сNone
, нет причин иметь более одного экземпляра этих классов, и если бы это было разрешено, было бы более неудобно проверять их (if x is None
должен был бы статьif isinstance(x, type(None))
). Я полагаю, в принципе, вы могли бы получить полный список, просматривая источник значенияtp_flags
в определениях типов. - person James   schedule 10.04.2012function
кажется ненужным — вместо этого вы можете использовать магический метод__call__
. Если ответ «Нет», то правило состоит в том, что только классы, которые могут быть полезными для подклассов, являются подклассами. - person agf   schedule 11.04.2012itemgetter
; и этот пост для почему вы можете захотеть создать подклассfunction
(это старый, поэтому некоторые из этих аргументов могут не применяться). - person max   schedule 11.04.2012itemgetter
- для текущего поведения равенства нет варианта использования (поскольку, если вы хотите такое поведение, вы используетеis
), поэтому нет причин для подкласса, а не для изменения поведения, кроме как обходной путь. Что касаетсяfunction
, все это либо возможно без создания подклассаfunction
, либо лучше сделать с вызываемым экземпляром пользовательского класса. Да, если бы все было подклассом, у нас было бы больше гибкости, но гибкость без варианта использования не является причиной в Python. - person agf   schedule 11.04.2012itemgetter
согласился на 100%, что более разумно (и намного проще!) Исправить поведение равенства, чем выполнять работу, необходимую для разрешения создания подклассов. Обсуждение подклассаfunction
было слишком сложным, чтобы я мог полностью его проследить; если вы считаете, что вариант использования для создания подклассов слаб, я бы поверил вам на слово. В целом, кажется, что ваши комментарии, похоже, напрямую связаны с двумя причинами, которые мы определили до сих пор: сломать что-то ‹=› одноэлементный шаблон; бесполезно ‹=› недостаточный интерес. Итак, я начинаю чувствовать, что мы близки к консенсусу. - person max   schedule 11.04.2012xrange
, также известный как Python 2range
, также известный какsix.moves.xrange
, не может быть подклассом. - person Bob Stein   schedule 09.06.2017memoryview
не является приемлемым базовым типом - person AJNeufeld   schedule 05.07.2018range
встроенная функция является еще одним важным примером, и она обсуждается в этом сообщении: stackoverflow.com/q/30362799/8844500 а> - person FraSchelle   schedule 05.01.2021