12.2. Operators Numerical

12.2.1. Rationale

Table 12.1. Numerical Operator Overload

Operator

Method

obj + other

obj.__add__(other)

obj - other

obj.__sub__(other)

obj * other

obj.__mul__(other)

obj / other

obj.__truediv__(other)

obj // other

obj.__floordiv__(other)

obj ** other

obj.__pow__(other)

obj % other

obj.__mod__(other)

obj @ other

obj.__matmul__(other)

obj += other

obj.__iadd__(other)

obj -= other

obj.__isub__(other)

obj *= other

obj.__imul__(other)

obj /= other

obj.__idiv__(other)

obj //= other

obj.__itruediv__(other)

obj **= other

obj.__ipow__(other)

obj %= other

obj.__imod__(other)

obj @= other

obj.__imatmul__(other)

-obj

obj.__neg__()

+obj

obj.__pos__()

~obj

obj.__invert__()

12.2.2. Operator Module

>>> from operator import add
>>> from operator import sub
>>> from operator import mul
>>> from operator import truediv
>>> from operator import floordiv
>>> from operator import mod
>>> from operator import pow
>>> from operator import matmul
>>> from operator import neg
>>> from operator import pos
>>> from operator import invert

12.2.3. Example

>>> from dataclasses import dataclass
>>>
>>>
>>> @dataclass
... class Vector:
...     x: int
...     y: int
...
...     def __add__(self, other):
...         new_x = self.x + other.x
...         new_y = self.y + other.y
...         return Vector(new_x, new_y)
...
...     def __iadd__(self, other):
...         self.x += other.x
...         self.y += other.y
...         return self
...
>>>
>>>
>>> a = Vector(x=1, y=2)
>>> b = Vector(x=3, y=4)
>>> c = Vector(x=5, y=6)
>>>
>>> (a+b) + c
Vector(x=9, y=12)
>>>
>>> a += Vector(x=10, y=20)
>>> print(a)
Vector(x=11, y=22)

12.2.4. Use Case - Mod

  • % (__mod__) operator behavior for int and str:

>>> 13 % 4
1
>>>
>>> '13' % '4'
Traceback (most recent call last):
TypeError: not all arguments converted during string formatting
>>> pi = 3.1514
>>>
>>>
>>> 'String: %s' % pi
'String: 3.1514'
>>>
>>> 'Double: %d' % pi
'Double: 3'
>>>
>>> 'Float: %f' % pi
'Float: 3.151400'
>>> firstname = 'Mark'
>>> lastname = 'Watney'
>>>
>>>
>>> 'Hello %s' % firstname
'Hello Mark'
>>>
>>> 'Hello %s %s' % (firstname, lastname)
'Hello Mark Watney'
>>>
>>> 'Hello %(fname)s %(lname)s' % {'fname': firstname, 'lname': lastname}
'Hello Mark Watney'
>>> class Str:
...     def __mod__(self, other):
...         """str substitute"""
...
...         if type(other) is str:
...             ...
...         if type(other) is tuple:
...             ...
...         if type(other) is dict:
...             ...

Note, that using %s, %d, %f is currently deprecated in favor of f'...' string formatting. More information in Builtin Printing

12.2.5. Assignments

Code 12.19. Solution
"""
* Assignment: Operators Numerical Matmul
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
    1. Overload `@` operator
    2. Set position based on argument `tuple[int, int]`
    3. Run doctests - all must succeed

Polish:
    1. Przeciąż operator `@`
    2. Ustaw pozycję na podstawie argumentu `tuple[int, int]`
    3. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> position = Position()
    >>> position
    Position(x=0, y=0)
    >>> position @ (1, 2)
    >>> position
    Position(x=1, y=2)
"""

from dataclasses import dataclass


@dataclass
class Position:
    x: int = 0
    y: int = 0


Code 12.20. Solution
"""
* Assignment: Operators Numerical IAdd
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
    1. Override operator `+=` for code to work correctly
    2. Run doctests - all must succeed

Polish:
    1. Nadpisz operatory `+=` aby poniższy kod zadziałał poprawnie
    2. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `obj.__iadd__(other) -> self`

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> astro = Astronaut(firstname='Jan', lastname='Twardowski', missions=[
    ...     Mission(1969, 'Apollo 11'),
    ... ])
    >>> astro += Mission(2024, 'Artemis 3')
    >>> astro += Mission(2035, 'Ares 3')

    >>> print(astro)  # doctest: +NORMALIZE_WHITESPACE
    Astronaut(firstname='Jan', lastname='Twardowski',
              missions=[Mission(year=1969, name='Apollo 11'),
                        Mission(year=2024, name='Artemis 3'),
                        Mission(year=2035, name='Ares 3')])
"""

from dataclasses import dataclass


@dataclass
class Astronaut:
    firstname: str
    lastname: str
    missions: list


@dataclass
class Mission:
    year: int
    name: str