Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dividing a number by instances of my class in Python

Tags:

I have a class called Time, and I need to implement a Frequency class. How can I implement dividing ints or floats by an instance of Time to get an instance of Frequency ?

I already know about __div__, __truediv__, __floordiv__ and other Python special methods, and I already use them in my code to divide instances of classes by numbers or instances of other classes, but I cannot find a way to divide a number by an instance of my class.

Is it possible to implement dividing a number by an instance of a class in Python ?

like image 420
lucidiot Avatar asked Jul 07 '17 12:07

lucidiot


People also ask

How do you divide a number in Python?

In Python, there are two types of division operators: / : Divides the number on its left by the number on its right and returns a floating point value. // : Divides the number on its left by the number on its right, rounds down the answer, and returns a whole number.

How do you divide an integer in Python?

In Python 3. x, slash operator ("/") does true division for all types including integers, and therefore, e.g. 3/2==1.5. The result is of a floating-point type even if both inputs are integers: 4 / 2 yields 2.0.


3 Answers

The __rtruediv__ method is what you're looking for. When x / y is executed, if type(x) does not implement a __div__(self, other) method where other can be of class type(y), then type(y).__rtruediv__(y, x) is executed, and its result is returned.

Usage:

class Foo:
    def __init__(self, x):
        self.x = x

    def __truediv__(self, other):
        return self.x / other

    def __rtruediv__(self, other):
        return other / self.x
>>> f = Foo(10)    
>>> f / 10
1.0
>>> 10 / f
1.0
like image 158
Right leg Avatar answered Oct 10 '22 09:10

Right leg


Yes. You just have to make sure that Time.__rtruediv__() returns a Frequency instance when it receives a float or integer.

Usage:

>>> 100 / Time(2)
Frequency(50.0)
>>> 2.5 / Time(5)
Frequency(0.5)

Implementation:

class Time:
  def __init__(self, value):
    self.value = value

  def __rtruediv__(self, other):
    if not isinstance(other, (int, float)):
      return NotImplemented
    return Frequency(other / self.value)

class Frequency:
  def __init__(self, value):
    self.value = value

  def __repr__(self):
    return '{}({})'.format(self.__class__.__name__, self.value)

The python docs contains a full example on implementing the arithmetic operations for your custom classes.

The proper way to handle incompatible types is to return the special value NotImplemented.

NotImplemented

Special value which should be returned by the binary special methods (e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to indicate that the operation is not implemented with respect to the other type

Suppose you try to use a unsupported complex number, returning NotImplemented will eventually cause a TypeError with a correct error message. (at least in python 3)

>>> 100j / Time(2)

Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'complex' and 'Time'
like image 27
Håken Lid Avatar answered Oct 10 '22 09:10

Håken Lid


you need to implement __rtruediv__ and__rfloordiv__.

from the documentation

object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rmatmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other)
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)

These methods are called to implement the binary arithmetic operations (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |) with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation [3] and the operands are of different types. [4] For instance, to evaluate the expression x - y, where y is an instance of a class that has an __rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns NotImplemented.

like image 45
hiro protagonist Avatar answered Oct 10 '22 10:10

hiro protagonist