Почему при вызове Python "магический метод" не выполняет преобразование типов, как это было бы для соответствующего оператора?
Когда я 1-2.0
число с плавающей точкой из целого числа (например, 1-2.0
), Python делает неявное преобразование типов (я думаю). Но когда я называю то, что считал одной и той же операцией, используя магический метод __sub__
, это неожиданно __sub__
быть.
Что мне здесь не хватает? Когда я перегружаю операторы для своих собственных классов, есть ли способ обойти это, кроме явного приведения ввода к тому типу, который мне нужен?
a=1
a.__sub__(2.)
# returns NotImplemented
a.__rsub__(2.)
# returns NotImplemented
# yet, of course:
a-2.
# returns -1.0
Ответы
Ответ 1
a - b
- это не просто a.__sub__(b)
. Он также пытается b.__rsub__(a)
если a
не может обработать операцию, а в случае 1 - 2.
это float __rsub__
который обрабатывает операцию.
>>> (2.).__rsub__(1)
-1.0
Вы запустили a.__rsub__(2.)
, Но это неправильно __rsub__
. Вам нужен правый операнд __rsub__
, а не левый операнд.
Не существует неявного преобразования типов, встроенного в оператор вычитания. float.__rsub__
должен обрабатывать int вручную. Если вы хотите преобразование типов в своих собственных реализациях операторов, вам придется обрабатывать это также вручную.
Ответ 2
@user2357112 уже хорошо сказал, но нет ничего похожего на пример.
class A:
def __sub__(self, other):
print('A.__sub__')
if not isinstance(other, A):
return NotImplemented
return 0
def __rsub__(self, other):
print('A.__rsub__')
if not isinstance(other, A):
return NotImplemented
return 0
class B:
def __sub__(self, other):
print('B.__sub__')
if not isinstance(other, B):
return NotImplemented
return 0
a1 = A()
a2 = A()
b = B()
a1 - a2
A.__sub__
# 0
Объекты a1
и a2
совместимы (оба типа A
), верный результат возвращается.
Далее рассмотрим,
b - a1
B.__sub__
A.__rsub__
# TypeError: unsupported operand type(s) for -: 'B' and 'A'
Объекты b
и a1
не совместимы. Сначала b.__sub__
, который возвращает NotImplemented
, поэтому a1.__rsub__
, который также возвращает NotImplemented
. Итак, TypeError
.
В заключение,
a1 - b
A.__sub__
# TypeError: unsupported operand type(s) for -: 'A' and 'B'
На этот раз a1.__sub__
, что возвращает NotImplemented
. Теперь, так как b.__rsub__
не определен, TypeError
приподнята.