У меня есть некоторые подклассы set
и frozenset
, OCDSet
и OCDFrozenSet
соответственно. Когда я использую их вместе с экземплярами своих классов-предков в двоичных операциях, классы предков доминируют над типом результата - под этим я имею в виду, когда я делаю что-то вроде вычитания OCDFrozenSet
из frozenset
, я получаю frozenset
... но тот же истинно, если я frozenset
типы в операции (т.е. frozenset
из OCDFrozenSet
.
Вот так:
... что особенно противоречиво досадно мне, тот факт, что использование -=
(subtract-in-place) мутирует тип существующего экземпляра!
Мои знания о том, как справляться с подобными вещами, берутся исключительно из C++, где тип операции - это упущенный вывод, который явно указан в (вероятной шаблонизированной) функции оператор-перегрузка; в Python система типов часто гораздо более неявная, но она не настолько непредсказуема, поскольку эта операция на месте заставила бы меня теперь верить.
Итак, что является наиболее целесообразным способом решения этого вопроса? Я предполагаю, что он включает в себя переопределение некоторых методов с двойным подчеркиванием в интересующих подклассах?
Операции на месте не гарантируют, что они будут обновлять объект на месте, он полностью зависит от типа объекта.
Tuple, frozenset и т.д. Являются неизменяемыми типами, поэтому их невозможно обновить на месте.
Из справочника библиотек операторов на месте:
Для неизменяемых целей, таких как строки, числа и кортежи, обновленное значение вычисляется, но не возвращается обратно к входной переменной.
Аналогичным образом в документах frozenset
также упоминается одно и то же о работе на месте [ источник ]:
В следующей таблице перечислены операции, доступные для набора, которые не применяются к неизменяемым экземплярам frozenset.
Теперь, поскольку ваш OCDFrozenSet
не реализует __isub__
, он будет __sub__
методу __sub__
который вернет тип базового класса frozenset
. Базовый класс используется, потому что Python не имеет представления о аргументах, которые ваш базовый класс ожидал бы от недавно созданного frozenset
из операции __sub__
.
Что еще более важно, это была ошибка в Python 2, где такая операция возвращала экземпляр подкласса, исправление было портировано только на Python 3, но для предотвращения нарушения существующих систем.
Чтобы получить ожидаемый результат, вы можете предоставить необходимые методы в вашем подклассе:
class OCDFrozenSet(frozenset):
def __sub__(self, other):
return type(self)(super().__sub__(other))
def __rsub__(self, other):
return type(self)(super().__rsub__(other))
__isub__(…)
на изменчивых изменчивых подклассах - так ли это?id()
будет другим, и другие ссылки на объект также не будут затронуты. Это просто совершенно новый объект, который присваивается переменной. Проверьте: repl.it/@ashwinichaudhary/WaryThisThing . Да,__isub__
подходит для вашего случая.