6.7. Operator Left¶
x + y
- will call method "add" on objectx
(x.__add__(y)
)x - y
- will call method "sub" on objectx
(x.__sub__(y)
)x * y
- will call method "mul" on objectx
(x.__mul__(y)
)x ** y
- will call method "pow" on objectx
(x.__pow__(y)
)x @ y
- will call method "matmul" on objectx
(x.__matmul__(y)
)x / y
- will call method "truediv" on objectx
(x.__truediv__(y)
)x // y
- will call method "floordiv" on objectx
(x.__floordiv__(y)
)x % y
- will call method "mod" on objectx
(x.__mod__(y)
)
Operator |
Method |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6.7.1. SetUp¶
>>> from dataclasses import dataclass
>>> from functools import reduce
6.7.2. Syntax¶
>>> @dataclass
... class Vector:
... x: int
... y: int
...
... def __add__(self, other): ... # x + y calls x.__add__(y)
... def __sub__(self, other): ... # x - y calls x.__sub__(y)
... def __mul__(self, other): ... # x * y calls x.__mul__(y)
... def __pow__(self, power, modulo=None): ... # x ** y calls x.__pow__(y)
... def __matmul__(self, other): ... # x @ y calls x.__matmul__(y)
... def __truediv__(self, other): ... # x / y calls x.__truediv__(y)
... def __floordiv__(self, other): ... # x // y calls x.__floordiv__(y)
... def __mod__(self, other): ... # x % y calls x.__mod__(y)
6.7.3. Example¶
>>> @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)
...
>>>
>>>
>>> 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)
6.7.4. Use Case - 0x01¶
Game
>>> hero @ Position(x=50, y=120)
>>>
>>> hero['gold'] += dragon['gold']
6.7.5. Use Case - 0x02¶
This is our function library.
Transformation functions (non-reducing) - takes one argument and returns one value:
>>> def increment(x):
... return x + 1
>>>
>>> def decrement(x):
... return x - 1
>>>
>>> def square(x):
... return x ** 2
>>>
>>> def cube(x):
... return x ** 3
Reducing functions - takes two arguments returns one value:
>>> def add(x, y):
... return x + y
>>>
>>> def sub(x, y):
... return x - y
>>>
>>> def mul(x, y):
... return x * x
We have data to compute:
>>> data = [
... [1, 2, 3],
... [4, 5, 6],
... [7, 8, 9],
... ]
On this data, we want to apply the following transformations:
>>> transformations = [increment, square, decrement, cube]
We need to create apply function, which takes data and apply the transformation:
>>> def apply(data, fn):
... return map(fn, data)
Let's do it parallel. We will create three independent workers. Each worker will get part of the data (one-third) and will apply all the transformation (map) to their data subset.
>>> workerA = reduce(apply, transformations, data[0]) # [27, 512, 3375]
>>> workerB = reduce(apply, transformations, data[1]) # [13824, 42875, 110592]
>>> workerC = reduce(apply, transformations, data[2]) # [250047, 512000, 970299]
Note, that all workers will produce generators (maps).
We need to merge the results using reduce
function,
but before that we need to evaluate maps to lists.
>>> def merge(x, y):
... return list(x) + list(y)
>>> merged = reduce(merge, [workerA, workerB, workerC])
>>> result = reduce(add, merged)
>>> print(result)
1903551
>>> print(merged)
[27, 512, 3375, 13824, 42875, 110592, 250047, 512000, 970299]
6.7.6. Assignments¶
"""
* Assignment: Operator Left 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