Python Knowledge
Eine etwas zufällige Sammlung von Dingen die ich im Masterstudium zu Python gelernt habe.
Python Module und Pakete
A Python module is simply a Python source file, which can expose classes, functions and global variables. When imported from another Python source file, the file name is treated as a namespace.
A Python package is simply a directory of Python module(s).
For example, imagine the following directory tree in /usr/lib/python/site-packages:
mypackage/init.py <-- this is what tells Python to treat this directory as a package mypackage/mymodule.py
So then you would do:
import mypackage.mymodule
or
from mypackage.mymodule import myclass
Decorators
Ein Decorator ist eine Funktion die eine andere Funktion mit zusätzlichem Code "dekoriert".
Der Decorator bekommt die Funktion func übergeben und führt in der Wrapper-Funktion Code aus bevor und nachdem func aufgerufen wird. So lassen sich Funktionen z.B. loggen, messen oder cachen.
def decorator(func):
def wrapper():
print("Before calling the function.")
func()
print("After calling the function.")
return wrapper
@decorator # Applying the decorator to a function
def greet():
print("Hello, World!")
greet()
Context Managers
Context Manager managen Kontext ;-) z.B geöffneten Dateien oder Datenbank Verbindungen. Ähnlich wie try-with-resources in Java.
with open('file.txt', 'w') as opened_file:
opened_file.write('Hello!')
Asyncio
Bester Einstieg in die Dokumentation
Exkurs: Javascript Event Loop: Sehr gutes Video um async in Javascript zu verstehen
Exkurs: What color is your function?: Blogpost über async/sync
Exkurs: Crossing the Asynchronous Divide
Event Loop
Die Event Loop ist das zentrale Element in der asyncio Library. Hier werden alle Tasks und Coroutinen in einer Art Warteschlange gespeichert "You can roughly think of the collection of jobs as a queue"
Coroutine
Das Wort Coroutine wird in der Python Dokumentation für zwei Dinge verwendet: Coroutine Funktionen und das Coroutine Objekt
Eine Funktion die mit async definiert wurde ist eine Coroutine Funktion
Wenn diese Funktion aufgerufen wird gibt sie ein Coroutine Objekt zurück.
Die Funktion wird dabei NICHT ausgeführt oder gestartet:
async def print_soon(str):
await asyncio.sleep(1)
print(str)
coro = afunc1("hello")
Coroutine Funktionen sollten einen try/catch Block haben falls die Ausführung der Coroutine abgebrochen wird. (asyncio.CancelledError)
Um eine Coroutine auszuführen muss sie awaited werden oder ein Task mir ihr erstellt werden.
Task
Kann um eine Coroutine gewickelt werden um sie zu starten.
Mit asyncio.create_task() wird ein Task erstellt und zum Ausführen an die get_running_loop() Event Loop gegeben.
Dafür wird ein Callback zum Task an die Event Loop Queue gehängt und die Aufrufende Funktion läuft weiter.
Wenn keine Referenz zum Task gespeichert wird kann er jetzt jederzeit vom Garbage Collector abgeräumt werden! Es wird nur ein Callback in der Queue gespeichert, NICHT der ganze Task.
Tasks können abgebrochen werden: task.cancel()
Tasks können auch als eager tasks erzeugt werden, diese fangen sofort an zu laufen bis sie auf ein await stoßen. Erst dann werden sie auf die Event Loop verschoben.
Awaitable und await
Coroutine, Tasks und Futures sind Awaitables. Awaitables können in await-Statements verwendet werden.
await verhält sich beim Aufrufen mit einer Coroutine anders als mit einem Task:
Da ein Task immer in einer Event Loop existiert gibt await task1 einfach nur die Kontrolle an die Event Loop zurück. Irgendwann wird der Task ausgeführt und wenn er fertig ist wird per Callback die aufrufende Funktion weiter ausgeführt.
await coro1() umgeht die Event Loop und führt die Coroutine coro1 sofort aus.
Das Verhalten von await coroutine() ist wie folgt:
- func1 läuft grade und und führt
await func2()aus. - func1 wird pausiert. func2 wird direkt ausgeführt ohne die Event Loop Queue zu berücksichtigen.
- func2 ruft
await func3()auf. - func2 wird pausiert. func3 wird direkt ausgeführt.
- func3 läuft ohne weiteres
awaitdurch - func2 wird per callback weiter ausgeführt und läuft zu Ende durch
- func1 wird per callback weiter ausgeführt
Tasks die in der Event Loop Queue sind kommen nur dran wenn alle async Funktionen abgearbeitet sind!
Async / Await in FastAPI
FastAPI Docs
Path Operation Functions (POF) mit async def (=Coroutine) werden an die Event Loop Queue angehangen.
POFs mit def werden in einem Threadpool ausgeführt.
Für ganz simple POFs sollten Coroutines verwendet werden, weil es schneller ist.
Für non-blocking IO müssen Coroutines verwendet werden weil wir nur in async Funktionen await verwenden können.
Für blocking IO müssen normale Funktionen in einem Threadpool verwendet werden weil die Event Loop sonst blockiert werden kann.
Was bedeutet das für die Datenbank Kommunikation? Die Datenbank Beispiele in der FastAPI Doku sind fast immer synchron/blockend. Damit müssen wir die Threadpool Variante benutzen? Das funktioniert aber nicht so einfach in der Websocket Kommunikation... Nein, es gibt auch async Module für Datenbanken.
FastAPI
Awesome FastAPI - Linksammlung zu Erweiterungen und Tools