6.8. Operator Increment

  • x += y - will call method "iadd" on object x (x.__iadd__(y))

  • x -= y - will call method "isub" on object x (x.__isub__(y))

  • x *= y - will call method "imul" on object x (x.__imul__(y))

  • x **= y - will call method "ipow" on object x (x.__ipow__(y))

  • x @= y - will call method "imatmul" on object x (x.__imatmul__(y))

  • x /= y - will call method "itruediv" on object x (x.__itruediv__(y))

  • x //= y - will call method "ifloordiv" on object x (x.__ifloordiv__(y))

  • x %= y - will call method "imod" on object x (x.__imod__(y))

Table 6.6. Numerical Operator Overload

Operator

Method

obj += other

obj.__iadd__(other)

obj -= other

obj.__isub__(other)

obj *= other

obj.__imul__(other)

obj **= other

obj.__ipow__(other)

obj @= other

obj.__imatmul__(other)

obj /= other

obj.__itruediv__(other)

obj //= other

obj.__ifloordiv__(other)

obj %= other

obj.__imod__(other)

>>> x = 0
>>> id(x)  
4406492680
>>>
>>> x += 1
>>> id(x)  
4406492712
>>> x = 1
>>> id(x)  
4406492712
>>>
>>> x += 0
>>> id(x)  
4406492712
>>> x = [1, 2, 3]
>>> id(x)  
4343115776
>>>
>>> x += [4, 5, 6]
>>> id(x)  
4343115776

6.8.1. SetUp

>>> from dataclasses import dataclass, field

6.8.2. Syntax

>>> @dataclass
... class Vector:
...     x: int
...     y: int
...
...     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)

6.8.3. Example

>>> @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)
>>>
>>> a += Vector(x=10, y=20)
>>> print(a)
Vector(x=11, y=22)

6.8.4. Add vs Iadd

>>> @dataclass
... class Vector:
...     x: int
...     y: int
...
...     def __add__(self, other):
...         return Vector(
...             x = self.x + other.x,
...             y = self.y + other.y)
>>>
>>>
>>> a = Vector(x=1, y=2)
>>>
>>> id(a)  
4435911632
>>>
>>> a += Vector(x=10, y=20)
>>> id(a)  
4435972432
>>>
>>> print(a)
Vector(x=11, y=22)
>>> @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)
>>>
>>> id(a)  
4437201808
>>>
>>> a += Vector(x=10, y=20)
>>> id(a)  
4437201808
>>>
>>> print(a)
Vector(x=11, y=22)

6.8.5. Use Case - 0x01

Imports:

>>> from dataclasses import dataclass, field
>>> from pprint import pprint

Definition:

>>> @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

Usage:

>>> ares3 = Crew()
>>> ares3 += Astronaut('Mark', 'Watney')
>>> ares3 += Astronaut('Melissa', 'Lewis')
>>> pprint(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')

6.8.6. Assignments

Code 6.52. Solution
"""
* Assignment: Operator Increment Add
* 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