Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Nächste Überarbeitung
Vorhergehende Überarbeitung
modul:m323:learningunits:lu03:callbacks [2024/03/28 14:07] – angelegt - Externe Bearbeitung 127.0.0.1modul:m323:learningunits:lu03:callbacks [2026/09/08 08:34] (aktuell) – Animation zur Umkehrung der Kontrolle eingebettet admin
Zeile 3: Zeile 3:
 Callback Funktionen sind eine klassische Anwendung von First-Class- und Higher-Order-Functions. Callback Funktionen sind eine klassische Anwendung von First-Class- und Higher-Order-Functions.
  
 +===== Animation: das Konzept hinter Callbacks =====
 +
 +Der erste Tab zeigt das Muster ohne jedes Framework: Ihre Funktion weiss, **was** geschehen soll, die fremde Funktion bestimmt, **wann** und **wie oft**. Man sieht die Übergabe nach unten und den Rückruf nach oben – und dass ein anderer Callback das Verhalten ändert, ohne dass am fremden Code etwas angepasst wird. Die beiden weiteren Tabs zeigen dasselbe Muster in echt: beim Button-Klick (samt dem Klammernfehler weiter unten) und beim nebenläufigen Warten.
 +
 +{{url>https://templates-python.github.io/m323_html/lu03/callbacks.html 100%,880px noborder|Animation: Callbacks, wer ruft wen und wann}}
  
 ===== Callbacks in der GUI Programmierung ===== ===== Callbacks in der GUI Programmierung =====
Zeile 35: Zeile 40:
  
 In diesem Beispiel ist ''on_button_click'' der Callback, der aufgerufen wird, wenn der Benutzer auf den Button klickt. In diesem Beispiel ist ''on_button_click'' der Callback, der aufgerufen wird, wenn der Benutzer auf den Button klickt.
 +
 +<WRAP center round tip 60%>
 +Achten Sie auf ''command=on_button_click'' – **ohne Klammern**. Die Funktion wird hier nicht aufgerufen, sondern nur //übergeben//. Mit ''command=on_button_click()'' würde die Funktion sofort beim Erstellen des Buttons einmal ausgeführt und dem Button anschliessend ihr Rückgabewert ''None'' übergeben – der Button täte danach beim Klicken gar nichts. Das ist einer der häufigsten Anfängerfehler in der GUI-Programmierung.
 +
 +Die beiden letzten Schritte im zweiten Tab der Animation oben zeigen genau diesen Fall.
 +</WRAP>
  
 ==== Fazit ==== ==== Fazit ====
Zeile 41: Zeile 52:
  
 ===== Callbacks in der Asynchronen Programmierung ===== ===== Callbacks in der Asynchronen Programmierung =====
 +
 +<WRAP center round info 60%>
 +Wir werden das asynchrone Programmieren nicht vertiefen am BZZ. Dies dürfen Sie dann an der Fachhochschule 😉
 +</WRAP>
 +
  
 Asynchrone Programmierung ist ein Ansatz, bei dem Operationen ausgeführt werden können, ohne den Ablauf des gesamten Programms zu blockieren. Ein häufiges Szenario für asynchrone Aufrufe sind Netzwerkanfragen, z. B. API-Aufrufe, bei denen nicht vorhersehbar ist, wie lange sie dauern werden. Asynchrone Programmierung ist ein Ansatz, bei dem Operationen ausgeführt werden können, ohne den Ablauf des gesamten Programms zu blockieren. Ein häufiges Szenario für asynchrone Aufrufe sind Netzwerkanfragen, z. B. API-Aufrufe, bei denen nicht vorhersehbar ist, wie lange sie dauern werden.
Zeile 66: Zeile 82:
   * **''await''**: Das Schlüsselwort ''await'' wird verwendet, um das Ergebnis einer asynchronen Operation abzurufen. Es kann nur innerhalb einer ''async''-Funktion verwendet werden.   * **''await''**: Das Schlüsselwort ''await'' wird verwendet, um das Ergebnis einer asynchronen Operation abzurufen. Es kann nur innerhalb einer ''async''-Funktion verwendet werden.
  
-=== Beispiele === 
  
-== Einfaches Beispiel mit sleep()==+=== Beispiel: Parallele Ausführung von Aufgaben ===
  
 +Eine der Hauptvorteile von asynchroner Programmierung ist die Fähigkeit, mehrere Aufgaben parallel auszuführen, insbesondere wenn es um Aufgaben geht, die auf externe Ressourcen warten, wie z.B. Netzwerkanfragen.
  
-Ein einfaches Beispiel für die Verwendung von ''async'' und ''await'':+<code python> 
 +import asyncio 
 + 
 +async def task_1(): 
 +    print('Task 1 gestartet') 
 +    await asyncio.sleep(2) 
 +    print('Task 1 abgeschlossen') 
 + 
 +async def task_2(): 
 +    print('Task 2 gestartet') 
 +    await asyncio.sleep(3) 
 +    print('Task 2 abgeschlossen') 
 + 
 +async def main(): 
 +    await asyncio.gather(task_1(), task_2()) 
 + 
 +if __name__ == '__main__': 
 +    asyncio.run(main()) 
 +</code> 
 + 
 +Die Ausgabe zeigt, worum es geht – **beide** Tasks starten, bevor einer davon fertig ist: 
 + 
 +<code> 
 +Task 1 gestartet 
 +Task 2 gestartet 
 +Task 1 abgeschlossen      (nach 2 Sekunden) 
 +Task 2 abgeschlossen      (nach 3 Sekunden) 
 +</code> 
 + 
 +Das ganze Programm dauert 3 Sekunden statt 5, weil die beiden Wartezeiten sich überlappen. Der dritte Tab der Animation oben zeigt diesen Ablauf auf einer Zeitachse, mit der sequenziellen Variante als Vergleich. 
 + 
 +=== Beispiel: Asynchrone Dateioperation === 
 + 
 +In diesem Beispiel zeigen wir, wie Dateioperationen asynchron ablaufen können. Das Beispiel liest den Inhalt von zwei Dateien asynchron.
  
 <code python> <code python>
 +import aiofiles
 import asyncio import asyncio
  
-async def say_hello(): +async def read_file(file_name): 
-    print("Hallo") +    async with aiofiles.open(file_name, 'r') as file: 
-    await asyncio.sleep(1) +        contents = await file.read() 
-    print("Welt") +        print(f'Inhalt von {file_name}: {contents}') 
-    + 
 +async def main(): 
 +    await asyncio.gather( 
 +        read_file('file1.txt'), 
 +        read_file('file2.txt') 
 +    ) 
 if __name__ == '__main__': if __name__ == '__main__':
-    asyncio.run(say_hello())+    asyncio.run(main())
 </code> </code>
  
-In diesem Beispiel wird die Funktion ''say_hello'' mit dem Schlüsselwort ''async'' definiert, was bedeutet, dass sie asynchron ist. Innerhalb dieser Funktion wird ''await'' verwendet, um die Ausführung für eine Sekunde zu pausieren, bevor ''Welt'' gedruckt wird.+=== Beispiel: API-Call mit Zeitüberschreitung ===
  
-== Beispiel mit API-Call ==+Ein häufiges Problem bei Netzwerkanfragen ist die Notwendigkeit, eine maximale Wartezeit festzulegen. Dies kann durch die Verwendung von Timeout-Parametern und asynchroner Programmierung gelöst werden.
  
-Dieses Beispiel ruft Daten von einer Dummy-API ab und verwendet ''async'' und ''await''. Um asynchrone HTTP-Anfragen in Python durchzuführen, können Sie die ''httpx''-Bibliothek verwenden. Dies ist eine moderne HTTP-Client-Bibliothek, die sowohl synchronen als auch asynchronen Code unterstützt.+Der Mock-Server antwortet erst nach 3 Sekunden (''mocky-delay=3000ms''), zugelassen sind aber nur 2 Sekunden (''timeout=2''). Dadurch wird der Fehlerzweig tatsächlich erreicht.
  
 <code python> <code python>
Zeile 97: Zeile 153:
 async def fetch_data(): async def fetch_data():
     async with httpx.AsyncClient() as client:     async with httpx.AsyncClient() as client:
-        response = await client.get('https://hub.dummyapis.com/delay?seconds=3') +        try: 
-        return response+            response = await client.get('https://run.mocky.io/v3/685db531-06e7-4d66-bbf6-99de9f2feab3?mocky-delay=3000ms', timeout=2) 
 +            print(response.text) 
 +        except httpx.RequestError as exc: 
 +            print(f'An error occurred while requesting data: {type(exc).__name__}') 
 +            # Ausgabe: An error occurred while requesting data: ReadTimeout
  
 async def main(): async def main():
-    result = await fetch_data() +    await fetch_data() 
-    print(result) +
-    +
 if __name__ == '__main__': if __name__ == '__main__':
     asyncio.run(main())     asyncio.run(main())
 +</code>
  
 +<WRAP center round tip 60%>
 +Zwei Details, die leicht übersehen werden:
 +
 +  * ''httpx.RequestError'' ist die Oberklasse aller Anfragefehler – ''ReadTimeout'' gehört dazu und wird von diesem ''except'' mitgefangen.
 +  * Bei einem Timeout ist ''str(exc)'' **leer**. Ein ''print(f''...: {exc}'')'' würde also eine abgeschnittene Meldung ohne jeden Hinweis ergeben. Deshalb wird hier ''type(exc).__name__'' ausgegeben.
 +
 +Setzt man ''timeout=5'', kommt die Antwort nach 3 Sekunden regulär an und der ''except''-Zweig wird nie erreicht.
 +</WRAP>
 +
 +=== Beispiel: Daten von mehreren APIs gleichzeitig abrufen ===
 +
 +Hier zeigen wir, wie mehrere API-Aufrufe parallel ablaufen können, um die Effizienz zu verbessern.
 +
 +<code python>
 +import httpx
 +import asyncio
 +
 +
 +async def fetch_data(url):
 +    async with httpx.AsyncClient() as client:
 +        response = await client.get(url)
 +        return response.text
 +
 +
 +async def main():
 +    urls = [
 +        'https://run.mocky.io/v3/685db531-06e7-4d66-bbf6-99de9f2feab3?mocky-delay=3000ms',
 +        'https://run.mocky.io/v3/685db531-06e7-4d66-bbf6-99de9f2feab3?mocky-delay=2000ms'
 +    ]
 +    results = await asyncio.gather(*(fetch_data(url) for url in urls))
 +    for result in results:
 +        print(result)
 +
 +
 +if __name__ == '__main__':
 +    asyncio.run(main())
 </code> </code>
  
 +Diese Beispiele zeigen verschiedene nützliche Anwendungsfälle für die asynchrone Programmierung in Python. Besonders bei I/O-intensiven Aufgaben hilft sie, die Blockierung des Programms zu vermeiden und die Gesamtleistung zu verbessern.
  
 ---- ----
-{{tag>M323-LU03}} +{{tag>M323-LU03 M323-C2I M323-C2A}} 
-[[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi +[[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi 
  • modul/m323/learningunits/lu03/callbacks.1711631267.txt.gz
  • Zuletzt geändert: 2024/03/28 14:07
  • von 127.0.0.1