## 8.1. Why to use operator overload?

• Simpler operations

```class Vector:
def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y

vector1 = Vector(x=1, y=2)
vector2 = Vector(x=3, y=4)

suma = vector1 + vector2
# TypeError: unsupported operand type(s) for +: 'Vector' and 'Vector'
```
```class Vector:
def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y

def __str__(self):
return f'Vector(x={self.x}, y={self.y})'

return Vector(
self.x + other.x,
self.y + other.y
)

vector1 = Vector(x=1, y=2)
vector2 = Vector(x=3, y=4)
vector3 = Vector(x=5, y=6)

suma = vector1 + vector2
print(suma)
# Vector(x=4, y=6)

suma = vector1 + vector2 + vector3
print(suma)
# Vector(x=9, y=12)
```

### 8.2.1. Numerical Operators

Operator

Method

`a + b`

`__add__()`

`a += b`

`__iadd__()`

`a - b`

`__sub__()`

`a -= b`

`__isub__()`

`a * b`

`__mul__()`

`a *= b`

`__imul__()`

`a / b`

`__div__()`

`a /= b`

`__idiv__()`

`a % b`

`__mod__()`

### 8.2.2. Comparison Operators

Operator

Method

`a == b`

`__eq__()`

`a != b`

`__ne__()`

`a < b`

`__lt__()`

`a <= b`

`__le__()`

`a > b`

`__gt__()`

`a >= b`

`__ge__()`

### 8.2.3. Boolean Operators

Operator

Method

`-a`

`__neg__()`

`+a`

`__pos__`

`a & b`

`__and__()`

`a | b`

`__or__()`

`a ^ b`

`__xor__()`

`a << b`

`__lshift__()`

`a >> b`

`__rshift__()`

### 8.2.4. Builtin Functions

Function

Method

`abs(a)`

`__abs__()`

`bool(a)`

`__bool__()`

`divmod(a, b)`

`__divmod__()`

`pow(a)`

`__pow__()`

`round(a, prec)`

`__round__()`

`dir(a)`

`__dir__()`

`len(a)`

`__len__()`

`delattr(cls, 'a')`

`__delattr__()`

`complex(a)`

`__complex__()`

`int(a)`

`__int__()`

`float(a)`

`__float__()`

`oct(a)`

`__oct__()`

`hex(a)`

`__hex__()`

`reversed()`

`__reversed__()`

```from math import sqrt

class Vector:
def __init__(self, x=0.0, y=0.0):
self.x = x
self.y = y

def __abs__(self):
return sqrt(self.x**2 + self.y**2)

vector = Vector(x=3, y=4)
abs(vector)
# 5.0
```

### 8.2.5. Builtin keywords

Keyword

Method

`del a`

`__delattr__()`

Operator

Description

`a[b]`

`__getitem__()`

`a[b] = 10`

`__setitem__()`

`a in b`

`__contains__()`

`a[b]` (when `b` is not in `a`)

`__missing__()`

## 8.3. Example

### 8.3.1. Modulo operator for `int` and `str`

```7 % 2               # 1
'My number' % 2     # TypeError: not all arguments converted during string formatting
'My number %s' % 2  # My number 2
'My number %d' % 2  # My number 2
'My number %f' % 2  # My number 2.0
```

Note

`%s`, `%d`, `%f` is currently deprecated in favor of `f'...'` string formatting. The topic will be continued in Print Formatting chapter.

### 8.3.2. Contains in `numpy`

```import numpy as np

a = np.array([[1, 2, 3],
[4, 5, 6]])

a[1][2]  # 6
a[1,2]   # 6
```
Listing 308. Intuitive implementation of numpy `array[row,col]` accessor
```class array(list):
def __getitem__(key):
row = key[0]
col = key[1]
return super().__getitem__(row).__getitem__(col)

# a[1,2]
a.__getitem__(key=(1,2))
```

## 8.4. Assignment

• Complexity level: easy

• Lines of code to write: 10 lines

• Estimated time of completion: 15 min

1. Dopisz odpowiednie metody do `Contact` i `Address` aby poniższy kod zadziałał poprawnie

```class Contact:
def __str__(self):
return f'{self.__dict__}'

def __repr__(self):
return f'{self.__dict__}'

Address(center='Kennedy Space Center', location='Merritt Island, FL'),
))

contact += Address(center='Armstrong Flight Research Center', location='Edwards AFB, CA'),

print(contact)
# {'first_name': 'Jan', 'last_name':'Twardowski', 'addresses': [
#       {'center': 'Johnson Space Center', 'location': 'Houston, TX'},
#       {'center': 'Kennedy Space Center', 'location': 'Merritt Island, FL'},
#       {'center': 'Jet Propulsion Laboratory', 'location': 'Pasadena, CA'},
#       {'center': 'Armstrong Flight Research Center', 'location': 'Edwards AFB, CA'}
# ]}

if Address(center='Armstrong Flight Research Center', location='Edwards AFB, CA') in contact:
print(True)
else:
print(False)
# True
```