11.8. Operator Arithmetic Increment

  • += - iadd

  • -= - isub

  • *= - imul

  • /= - idiv

  • //= - itruediv

  • **= - ipow

  • %= - imod

  • @= - imatmul

11.8.1. About

Table 11.3. Numerical Operator Overload

Operator

Method

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)

11.8.2. Example

>>> class Vector:
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
...     def __repr__(self):
...         return f'Vector(x={self.x}, y={self.y})'
...
...     def __iadd__(self, other): ...              # x += y    calls x.__iadd__(y)
...     def __isub__(self, other): ...              # x -= y    calls x.__isub__(y)
...     def __imul__(self, other): ...              # x *= y    calls x.__imul__(y)
...     def __ipow__(self, power, modulo=None): ... # x **= y   calls x.__ipow__(y)
...     def __imatmul__(self, other): ...           # x @= y    calls x.__imatmul__(y)
...     def __itruediv__(self, other): ...          # x /= y    calls x.__itruediv__(y)
...     def __ifloordiv__(self, other): ...         # x //= y   calls x.__ifloordiv__(y)
...     def __imod__(self, other): ...              # x %= y    calls x.__imod__(y)

11.8.3. Increment Operation

>>> from dataclasses import dataclass
>>> @dataclass
... class Vector:
...     x: int
...     y: int
...
...     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 += Vector(x=10, y=20)
>>> print(a)
Vector(x=11, y=22)

11.8.4. Use Case - 0x01

>>> from dataclasses import dataclass, field
>>>
>>>
>>> @dataclass
... class Astronaut:
...     firstname: str
...     lastname: str
>>>
>>>
>>> @dataclass
... class Crew:
...     members: list[Astronaut] = field(default_factory=list)
...
...     def __iadd__(self, other):
...         self.members.append(other)
...         return self
>>>
>>>
>>> ares3 = Crew()
>>> ares3 += Astronaut('Mark', 'Watney')
>>> ares3 += Astronaut('Melissa', 'Lewis')
>>>
>>> print(ares3)
Crew(members=[Astronaut(firstname='Mark', lastname='Watney'), Astronaut(firstname='Melissa', lastname='Lewis')])
>>>
>>> for member in ares3.members:
...     print(member)
Astronaut(firstname='Mark', lastname='Watney')
Astronaut(firstname='Melissa', lastname='Lewis')

11.8.5. Assignments

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

English:
    1. Make object understand following call: `position @ (1, 2)`
    1. Overload `@` operator, to take `tuple[int, int]` as argument
    2. Set `x` and `y` coordinates based on passed values
    3. Run doctests - all must succeed

Polish:
    1. Spraw aby obiekt obsługiwał to wywołanie: `position @ (1, 2)`
    1. Przeciąż operator `@`, aby przyjmował `tuple[int, int]` jako argument
    2. Zmień koordynaty `x` i `y` na podstawie przekazanych wartości
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `object.__matmul__()`

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 11.31. Solution
"""
* Assignment: Operator Numerical IAdd
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
    1. Overload operator `+=`
    2. Make `Astronaut` objects able to add `Missions`, for example:
       a. `mark = Astronaut(firstname='Mark', lastname='Watney')`
       b. `mark += Mission(2035, 'Ares3')`
       c. `mark += Mission(2040, 'Ares5')`
    3. Run doctests - all must succeed

Polish:
    1. Przeciąż operator `+=`
    2. Spraw aby do obiektów klasy `Astronaut` można dodać `Mission`, przykład:
       a. `mark = Astronaut(firstname='Mark', lastname='Watney')`
       b. `mark += Mission(2035, 'Ares3')`
       c. `mark += Mission(2040, 'Ares5')`
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `object.__iadd__() -> self`

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

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

    >>> print(astro)  # doctest: +NORMALIZE_WHITESPACE
    Astronaut(firstname='Mark', lastname='Watney',
              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