Как я могу сделать так, чтобы мои подклассы Python `set` и` frozenset` сохраняли свои типы при участии в бинарных операциях? - PullRequest
0 голосов
/ 16 октября 2018

У меня есть некоторые set и frozenset подклассы, OCDSet и OCDFrozenSet соответственно.Когда я использую их вместе с экземплярами их классов-предков в бинарных операциях, классы-предки доминируют над типом результата - я имею в виду, когда я делаю что-то вроде вычитания OCDFrozenSet из frozenset, я получаю frozenset… но то же самое верно, если я переворачиваю типы в операции (т.е. вычитаю frozenset из OCDFrozenSet.

Примерно так:

enter image description here

… что меня особенно раздражает, так это то, что использование -= (вычитание на месте) изменяет тип существующего экземпляра!

Мои знания о том, какчтобы иметь дело с такого рода вещами строго из C ++, где тип операции является заброшенным выводом, который явно указан в (вероятно, шаблонной) функции перегрузки оператора, в Python система типов часто намного более неявна, но онане настолько непредсказуемо, как эта операция на месте заставила бы меня поверить.

Итак, что является наиболее целесообразным способом решения этой проблемы - я полагаю,t предполагает переопределение некоторых методов экземпляров с двойным подчеркиванием в интересующих подклассах?

1 Ответ

0 голосов
/ 16 октября 2018

Операции на месте не гарантируют, что они обновят объект на месте, они полностью зависят от типа объекта.

Tuple, frozenset и т. Д. Являются неизменяемыми типами, следовательно, этоневозможно обновить их на месте.

С ссылка на библиотеку для операторов на месте:

Для неизменяемых целей, таких как строки, числа и кортежиобновленное значение вычисляется, но не присваивается обратно входной переменной.

Аналогично, в документах frozenset также упоминается то же самое в операциях на месте [ source ]:

В следующей таблице перечислены операции, доступные для набора, которые не применяются к неизменяемым экземплярам frozenset.


Теперь, как вашOCDFrozenSet не реализует __isub__, он вернется к методу __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))
...