# 12.6. Operators Accessors¶

## 12.6.1. Rationale¶

Operator

Method

Remarks

obj(x)

obj.__call__(x)

obj[x]

obj.__getitem__(x)

obj[x]

obj.__missing__(x)

(when x is not in obj)

obj[x] = 10

obj.__setitem__(x, 10)

del obj[x]

obj.__delitem__(x)

x in obj

obj.__contains__(x)

## 12.6.2. Example¶

>>> def echo(text):
...     return text
>>>
>>>
>>> echo('Mark Watney')
'Mark Watney'
>>>
>>> echo.__call__('Mark Watney')
'Mark Watney'


## 12.6.3. Use Case¶

>>> data = slice(1, 2, 3)
>>>
>>>
>>> data.start
1
>>>
>>> data.stop
2
>>>
>>> data.step
3

>>> class MyClass:
...     def __getitem__(self, item):
...         print(item)
>>>
>>>
>>> my = MyClass()
>>>
>>> my[1:2]
slice(1, 2, None)

>>> data = dict()
>>>
>>> data['a'] = 10  # data.__setitem__('a', 10) -> None
>>> data['a']       # data.__getitem__('a') -> 10
10
>>>
>>> data['x']       # data.__getitem__('x') -> data.__missing__() -> KeyError: 'x'
Traceback (most recent call last):
KeyError: x
>>>
>>> data()          # data.__call__() -> TypeError: 'dict' object is not callable
Traceback (most recent call last):
TypeError: 'dict' object is not callable


Getitem in numpy:

>>> import numpy as np
>>>
>>>
>>> data = np.array([[1, 2, 3],
...                  [4, 5, 6]])
>>>
>>> data[1][2]
6
>>>
>>> data[1,2]
6
>>>
>>> data[1:2]
array([[4, 5, 6]])
>>>
>>> data[1:2, 0]
array([4])
>>>
>>> data[1:2, 1:]
array([[5, 6]])


Intuitive implementation of numpy array[row,col] accessor:

>>> class array(list):
...     def __getitem__(key):
...         if isinstance(key, int):
...             return super().__getitem__(key)
...
...         if isinstance(key, tuple):
...             row = key[0]
...             col = key[1]
...             return super().__getitem__(row).__getitem__(col)
...
...         if isinstance(key, slice):
...             start = key[0] if key[0] else 0
...             stop = key[1] if key[0] else len(self)
...             step = key[2] if key[2] else 1
...             return ...
>>>
>>>
>>> data[1]         # data.__getitem__(1)
array([4, 5, 6])
>>>
>>> data[1,2]       # data.__getitem__((1,2))
6
>>>
>>> data[1:2]       # data.__getitem__(1:2)  # data.__getitem__(slice(1,2))
array([[4, 5, 6]])
>>>
>>> data[:, 2]      # data.__getitem__((:, 2))  # data.__getitem__((slice(), 2))
array([3, 6])


## 12.6.4. Use Case - Cache¶

>>> class Cache(dict):
...     def __init__(self, func):
...         self.func = func
...
...     def __call__(self, *args):
...         return self[args]
...
...     def __missing__(self, key):
...         self[key] = self.func(*key)
...         return self[key]
>>>
>>>
>>> @Cache
...     return a + b
>>>
>>>
>>> _ = add(1,2)  # computed
>>> _ = add(1,2)  # fetched from cache
>>> _ = add(1,2)  # fetched from cache
>>> _ = add(1,2)  # fetched from cache
>>> _ = add(2,1)  # computed
>>> _ = add(2,1)  # fetched from cache
>>>
{(1, 2): 3,
(2, 1): 3}


## 12.6.5. Assignments¶

"""
* Assignment: Operators Accessors Contains
* Complexity: easy
* Lines of code: 5 lines
* Time: 8 min

English:
1. Override operators for code to work correctly
2. Do not use dataclasses
3. Run doctests - all must succeed

Polish:
2. Nie używaj dataclasses
3. Uruchom doctesty - wszystkie muszą się powieść

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

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

>>> Mission(2035, 'Ares 3') == Mission(2035, 'Ares 3')
True
>>> Mission(2035, 'Ares 3') == Mission(1973, 'Apollo 18')
False
>>> Mission(2035, 'Ares 3') == Mission(2035, 'Apollo 18')
False
>>> Mission(2035, 'Ares 3') == Mission(1973, 'Ares 3')
False

>>> Mission(2024, 'Artemis 3') in astro
True
>>> Mission(1973, 'Apollo 18') in astro
False
"""

class Mission:
year: int
name: str

def __init__(self, year: int, name: str) -> None:
self.year = year
self.name = name

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

def __init__(self, firstname: str, lastname: str, missions: list) -> None:
self.firstname = firstname
self.lastname = lastname
self.missions = missions