tut14
This commit is contained in:
@ -0,0 +1,153 @@
|
|||||||
|
---
|
||||||
|
marp: true
|
||||||
|
paginate: true
|
||||||
|
# class: invert
|
||||||
|
theme: rose-pine
|
||||||
|
footer: Tutorium 14 - 26.01.2024 - Nils Pukropp - https://s.narl.io/s/tutorium-14
|
||||||
|
header:
|
||||||
|
math: mathjax
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tutorium 14 - 02.02.2024
|
||||||
|
|
||||||
|
Decorator, Testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Decorator
|
||||||
|
|
||||||
|
- **Design-Pattern**, oft auch **Wrapper** genannt
|
||||||
|
- Verpackt ein Objekt um **zusätzliche Funktionalität** zu bieten
|
||||||
|
- Funktionen sind auch Objekte
|
||||||
|
- eine Klasse ist ein Objekt
|
||||||
|
- Oft einfach **syntax sugar**
|
||||||
|
|
||||||
|
---
|
||||||
|
## Beispiel - execute_two_times
|
||||||
|
|
||||||
|
```python
|
||||||
|
def execute_two_times(fn: Callable[..., Any]) -> Callable[..., Any]:
|
||||||
|
def wrapper(*args, **kwargs)
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@execute_two_times()
|
||||||
|
def print_two_times(msg: str):
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
print_two_times("hello") # hello
|
||||||
|
# hello
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - execute_by
|
||||||
|
|
||||||
|
```python
|
||||||
|
def execute_by(n: int):
|
||||||
|
def wrapper(fn):
|
||||||
|
def wrapped_fn(*args, **kwargs):
|
||||||
|
for _ in range(0, n):
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
return wrapped_fn
|
||||||
|
return wrapped_fn
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@execute_by(10)
|
||||||
|
def print_ten_times(msg: str):
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
print_ten_times("hello") # hello
|
||||||
|
# hello
|
||||||
|
# ... (10 mal)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - CommandExecutor
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CommandExecutor[R]:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__commands: dict[str, Callable[..., R]] = {}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - run
|
||||||
|
|
||||||
|
```python
|
||||||
|
def run(self, name: str, *args, **kwargs) -> list[R]:
|
||||||
|
results : list[R] = []
|
||||||
|
for command_name, command in self.__commands.items():
|
||||||
|
if command_name == name:
|
||||||
|
results += [command(*args, **kwargs)]
|
||||||
|
return results
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - register
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register(self, cmd: Callable[..., R]) -> Callable[..., R]:
|
||||||
|
self.__commands[cmd.__name__] = cmd
|
||||||
|
return cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - CommandExecutor
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CommandExecutor[R]:
|
||||||
|
def __init__(self):
|
||||||
|
self.__commands: dict[str, Callable[..., R]] = {}
|
||||||
|
|
||||||
|
def run(self, name: str, *args, **kwargs) -> list[R]:
|
||||||
|
results : list[R] = []
|
||||||
|
for command_name, command in self.__commands.items():
|
||||||
|
if command_name == name:
|
||||||
|
results += [command(*args, **kwargs)]
|
||||||
|
return results
|
||||||
|
|
||||||
|
def register(self, cmd: Callable[..., R]) -> Callable[..., R]:
|
||||||
|
self.__commands[cmd.__name__] = cmd
|
||||||
|
return cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beispiel - How to use
|
||||||
|
|
||||||
|
```python
|
||||||
|
app = CommandExecutor[str]()
|
||||||
|
|
||||||
|
@app.register
|
||||||
|
def hello_world() -> str:
|
||||||
|
return 'hello_world'
|
||||||
|
|
||||||
|
@app.register
|
||||||
|
def divide(a: int, b: int) -> str:
|
||||||
|
if b == 0:
|
||||||
|
return "tried to divide by zero"
|
||||||
|
return str(a / b)
|
||||||
|
|
||||||
|
print(app.run('hello_world'))
|
||||||
|
print(app.run('divide', 5, 0))
|
||||||
|
print(app.run('divide', 10, 2))
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decorator in der Klausur
|
||||||
|
|
||||||
|
- Waren noch nie Bestandteil der Klausur
|
||||||
|
- Mut zur Lücke
|
||||||
|
- Kann euch natürlich nichts versprechen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Testing mit `pytest`
|
36
Tutorium/tut14/src/commands.py
Normal file
36
Tutorium/tut14/src/commands.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from typing import Callable, Iterator
|
||||||
|
|
||||||
|
|
||||||
|
class CommandExecutor[R]:
|
||||||
|
def __init__(self):
|
||||||
|
self.__commands: dict[str, Callable[..., R]] = {}
|
||||||
|
|
||||||
|
def run(self, name: str, *args, **kwargs) -> list[R]:
|
||||||
|
results : list[R] = []
|
||||||
|
for command_name, command in self.__commands.items():
|
||||||
|
if command_name == name:
|
||||||
|
results += [command(*args, **kwargs)]
|
||||||
|
return results
|
||||||
|
|
||||||
|
def register(self, cmd: Callable[..., R]) -> Callable[..., R]:
|
||||||
|
self.__commands[cmd.__name__] = cmd
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = CommandExecutor[str]()
|
||||||
|
|
||||||
|
@app.register
|
||||||
|
def hello_world() -> str:
|
||||||
|
return 'hello_world'
|
||||||
|
|
||||||
|
@app.register
|
||||||
|
def divide(a: int, b: int) -> str:
|
||||||
|
if b == 0:
|
||||||
|
return "tried to divide by zero"
|
||||||
|
return str(a / b)
|
||||||
|
|
||||||
|
print(app.run('hello_world'))
|
||||||
|
print(app.run('divide', 5, 0))
|
||||||
|
print(app.run('divide', 10, 2))
|
||||||
|
|
67
Tutorium/tut14/src/decorator.py
Normal file
67
Tutorium/tut14/src/decorator.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
|
||||||
|
def count_calls[T](func: Callable[..., T]) -> Callable[..., T]:
|
||||||
|
count_calls.calls = 0
|
||||||
|
def wrapper(*args, **kwargs) -> T:
|
||||||
|
init_calls = count_calls.calls
|
||||||
|
count_calls.calls += 1
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
wrapper.calls = count_calls.calls - init_calls
|
||||||
|
return result
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def f(x: int, y: int) -> int:
|
||||||
|
if x % 2 == 0:
|
||||||
|
return x // 2
|
||||||
|
else:
|
||||||
|
return x + 2 * y - 1
|
||||||
|
|
||||||
|
def count_iterations(a: int, b: int) -> int:
|
||||||
|
f_a(a, a, b)
|
||||||
|
return f_a.calls - 1
|
||||||
|
|
||||||
|
@count_calls
|
||||||
|
def f_a(init: int, a: int, b: int) -> None:
|
||||||
|
if a < b:
|
||||||
|
return
|
||||||
|
return f_a(init, f(a, init), b)
|
||||||
|
|
||||||
|
def execute_by(n: int):
|
||||||
|
def wrapper(fn):
|
||||||
|
def wrapped_fn(*args, **kwargs):
|
||||||
|
for _ in range(0, n):
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
return wrapped_fn
|
||||||
|
return wrapped_fn
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@execute_by(10)
|
||||||
|
def hello_world():
|
||||||
|
print('hello world!')
|
||||||
|
|
||||||
|
@execute_by(10)
|
||||||
|
def print_ten_times(msg: str):
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def execute_two_times(fn) -> Callable[..., Any]:
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
for _ in range(0, 2):
|
||||||
|
fn(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@execute_two_times
|
||||||
|
def test(msg: str):
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
assert (i := count_iterations(7, 6)) == 3, i
|
||||||
|
assert (i := count_iterations(3, 2)) == 4, i
|
||||||
|
assert (i := count_iterations(13, 9)) == 18, i
|
||||||
|
assert (i := count_iterations(13, 10)) == 8, i
|
||||||
|
assert (i := count_iterations(3, 4)) == 0, i
|
||||||
|
print_ten_times("hello world")
|
||||||
|
test("hello")
|
||||||
|
|
Reference in New Issue
Block a user