Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: rtruediv does not work as I expect

Using V3 of python, I create:

class NewInt(int):
  def __rtruediv__(self, num):
    print('in here')

x = NewInt(5)

343 / x    # called rtruediv as I expect, but

343.3 / x  # does not call rtruediv

Not sure why this is because:

x / 343
x / 343.3   #both will call truediv

To me, this seems inconsistent ..

Anyone have an explanation of why this is.. and when Python does 343.3 / x is there a method that can be overridden ?

I found this behaviour when reviewing some information on over-loading and came across this inconsistency.

Dave

like image 910
Dave Avatar asked May 18 '16 21:05

Dave


2 Answers

In short, the left operand gets the first shot at handling the operation, except under some special circumstances.

The relevant documentation here is in emulating numeric types:

Note: If the right operand's type is a subclass of the left operand's type and that subclass provides the reflected method for the operation, this method will be called before the left operand's non-reflected method. This behavior allows subclasses to override their ancestors' operations.

So in the case of:

343.3 / x  # does not call __rtruediv__

The left hand wins because float division by int is defined, and NewInt is an int. That is, 343.3.__truediv__(x) succeeds without error.

Let's reconcile all four cases in light of the documentation to see that there is not really any inconsistent behaviour here:

343 / x     # x.__rtruediv__ wins because NewInt subclasses int
343.3 / x   # 343.3.__truediv__ wins because NewInt doesn't subclass float
x / 343     # x.__truediv__ wins because int doesn't subclass NewInt
x / 343.3   # x.__truediv__ wins because float doesn't subclass NewInt
like image 182
wim Avatar answered Nov 16 '22 02:11

wim


__rtruediv__ only has priority over __truediv__ if the right-hand operand is an instance of a subclass of the left-hand operand's class.

When you do 343 / x, NewInt is a subclass of int, so x's __rtruediv__ gets priority. When you do 343.3 / x, NewInt is not a subclass of float, so 343.3's __truediv__ gets priority.

343.3.__truediv__(x) doesn't return NotImplemented, since float knows how to divide a float by an int. Thus, x.__rtruediv__ doesn't get called.

like image 5
user2357112 supports Monica Avatar answered Nov 16 '22 01:11

user2357112 supports Monica