Modularisierung#

Midjourney: Modular Blocks, ref. Piet Mondrian

Write programs that do one thing and do it well.

— Doug McIlroy

Folien/PDF#

Code in Dateien, Module und Pakete aufteilen#

Größere Programme enthalten oft dutzende Klassen mit hunderten Funktionen und vielen tausend Zeilen Code. Hier wird es sehr schnell schwer einen Überblick zu behalten, wenn alle Klassen in einer Datei definiert sind. Insbesondere wenn verschiedene Programmierer an verschiedenen Stellen im Programm arbeiten, kommt es dann sehr schnell zu Versionskonflikten, wenn Leute an ähnlichen Dateien arbeiten.

Um dies organisiert und übersichtlich zu halten, wird Code in mehrere Dateien mit der Erweiterung .py aufgespalten. Dabei ist es üblich jeweils eine Datei

  • pro Klasse, wenn Klassen definiert werden

  • pro Thema, wenn Hilfsfunktionen definiert werden (z.B. Mathematik-Funktionen, …)

  • pro Aufgabenbereich, wenn (z.B. Laden von Daten getrennt von deren Verarbeitung. So kann man z.B. später andere Verarbeitungsschritte definieren und das Laden wiederverwenden)

Speichern wir jede Klasse der Geometrieelemente aus dem Teil der Klassendefinition aus der letzten Vorlesung so hätten wir dann z.B. eine Projektstruktur entsprechend:

Dabei enthält jede Datei nur den Code der gleichnamigen Klasse, auch wenn dies nur wenige Zeilen sind, wie im Fall der Klassen Triangle, Tetragon und Pentagon. Entscheidend ist, dass wenn ein Programmierer nach dem Code für eine Klasse sucht, er genau sieht in welcher Datei dieser zu finden ist und nicht groß suchen muss.

Noch größere Projekte spalten man in mehrere Module indem man weitere Unterverzeichnisse anlegt. So wollen wir z.B. alle generischen Klassen für Punkte in das Verzeichnis points gruppieren und alle geometrischen Formen in das Verzeichnis shapes. So lassen sich größere Projekte gut strukturieren.

Die Summe aller Module formt dann ein Package. In diesem Fall das Package geometry, welches wir in verschiedenen Implementierungen wieder verwenden können.

main() - Der Startpunkt eines Programmes#

Wenn Code über mehrere Dateien verteilt ist, braucht Python einen Hinweis welcher Code ausgeführt werden soll. Hierfür definiert man die spezielle Einstiegsfunktion main(). Sie gibt es in fast allen Programmiersprachen und gibt immer den Startpunkt eines Programms an.

In Python hat sie entweder keine Argumente oder sie erhält diese dynamisch, wenn sie vom Nutzer / von einem anderen Programm aufgerufen wird (a.k.a. Kommandozeilenargumente).

def main():
	print("This is the main function")

Allerdings möchte man vermeiden, dass die Funktion main() auch aufgerufen wird, wenn die Python-Datei zum Beispiel als Bibliothek eingebunden wird, wo man nur an den Funktionen interessiert ist. Deshalb nutzt man am Ende einer Datei mit einer main()-Funktion die folgende Verzweigung.

if __name__ == "__main__":
	main()
This is the main function

Sie nutzt aus, dass der Wert der Standardvariable __name__ in der Hauptdatei immer '__main__' lautet. Während sie in einer importierten Datei den Namen der Hauptdatei angibt.

Importieren von Modulen#

Um zu vermeiden, dass ständig unnötiger Code geladen wird lädt Python diesen Code nicht automatisch. Wollen wir also den Code in unseren Dateien, Modulen und Packages nutzen so müssen wir vorher Python anweisen diesen zu laden. Dieses Importieren weist man mit dem Befehl import an.

Ein einfacher Import ist der import ganzer Pakete. Dies geschieht, indem wir import und dem Paketnamen schreiben.

import geometry.points.ImmutablePoint
import geometry.shapes.Line

def main():
	point_1 = geometry.points.ImmutablePoint.ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = geometry.points.ImmutablePoint.ImmutablePoint(y=12.094167, x=54.075211)
	linie_1 = geometry.shapes.Line.Line(start=point_1, end=point_2)
	print(f"Die Länge der Linie zwischen Punkt 1 und 2 ist: {linie_1.length()}")

if __name__ == "__main__":
	main()
Die Länge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

Der Nachteil des Imports ganzer Pakete ist, dass wenn wir hieraus einzelne Klassen referenzieren wollen, die sich in Untermodulen befinden, so müssen wir den kompletten Pfad der Klasse angeben. In dem Beispiel oben zum Beispiel geometry.points.ImmutablePoint.ImmutablePoint.

Deshalb importiert man meist einzelne Module indem man den Pfad eines Moduls angibt, wie zum Beispiel geometry.points.ImmutablePoint.ImmutablePoint. Hierbei kann man den importierten Modulen auch neue Namen geben wie point oder line in dem Beispiel unten.

import geometry.points.ImmutablePoint as point
import geometry.shapes.Line as line

def main():
	point_1 = point.ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = point.ImmutablePoint(y=12.094167, x=54.075211)
	linie_1 = line.Line(start=point_1, end=point_2)
	print(f"Die Länge der Linie zwischen Punkt 1 und 2 ist: {linie_1.length()}")

if __name__ == "__main__":
	main()
Die Länge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

Alternativ lassen sich auch Teile eines Moduls mit dem Platzhalter * und dem Befehl from importieren. Alle Elemente werden mit dem Platzhalter * importiert. Spezifische Elemente wie einzelne Klassen können auch direkt angegeben werden, wie im folgenden Beispiel Line.

from geometry.points.ImmutablePoint import *
from geometry.shapes.Line import Line

def main():
	point_1 = ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = ImmutablePoint(y=12.094167, x=54.075211)
	linie_1 = Line(start=point_1, end=point_2)
	print(f"Die Länge der Linie zwischen Punkt 1 und 2 ist: {linie_1.length()}")

if __name__ == "__main__":
	main()
Die Länge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

Standard Paktete aus Python importieren#

Python beinhaltet viele Standardpakete für typische Aufgaben. Für die Bau- und Umweltinformatik sind die folgenden am sinnvollsten:

packet

description

collections

Mehr komplexe Datentypen zum zählen, sortieren

http

Funktionen des HTTP-Internetprotokolls wie Web-Server

json

Funktionen um Objekte als Text abzuspeichern

logging

Funktionen um Logs zu schreiben

math

Mathematische Funktionen

os

Funktionen um Dateien zu finden, laden und speichern

pickle

Funktionen um Objekte binär abzuspeichern

pprint

print-Funktionen um Objekte schöner (pretty) auszugeben

random

Funktionen zum Erzeugen von Zufallszahlen

re

Funktionen für Reguläre Ausdrücke um Text zu suchen

sys

Funktionen um Systeminformationen zu erhalten

time

Funktionen für Zeit und Datumsangaben

timeit

Funktionen um die Performance von Funktionen zu testen

traceback

Funktionen um den Stack aufzulisten

urllib

Funktionen um ULRs im Internet zu laden und verarbeiten

Von der Liste haben wir die Bibliotheken math, time, timeit, traceback und logging schon kennen gelernt und benutzt. Die anderen Pakete bieten allerdings weitere sinnvolle Funktionen.

Wollen wir zum Beispiel alle Dateien in einem Verzeichnis auflisten, so nutzen wir das Paket os.

import os

folder = "geometry/shapes/"
for count, filename in enumerate(os.listdir(folder)):
	if os.path.isfile(os.path.join(folder, filename)):
		path = os.path.join(folder, filename)
		print(path)
geometry/shapes/Tetragon.py
geometry/shapes/Pentagon.py
geometry/shapes/Line.py
geometry/shapes/Polygon.py
geometry/shapes/Triangle.py

Viele Webseiten bieten Programmierschnittstellen an, so genannte APIs, da diese APIs auch von den eigenen Webseiten genutzt werden, um Daten nachzuladen, die auf der Webseite angezeigt werden. Die APIs nutzen meist das JSON-Format um Daten auszutauschen. Dies ist ein Text-basiertes Dateiformat, das in Python sehr stark dem dict-Datentyp ähnelt, aber auch alle anderen primitiven und zusammengesetzten Datentypen von Python unterstützt.

Wir möchten zum Beispiel die Wetterdaten einer Wetterstation in Deutschland analysieren. Diese Daten bekommen wir beim Deutschen Wetterdiest. Diese Daten kann man sich auch von der API herunterladen. Hierfür braucht man die ID (Identifikationsnummer) einer Wetterstation welche hier zu finden ist. Wir nehmen als Beispiel eine Station im Hansaviertel in Rostock mit der ID 12495.

Dann kann man die Wetterdaten mit Python mit Hilfe des Paketes urllib von der API laden. Das JSON-Format können wir mit dem json Paket verarbeiten. Wir laden dazu zuerst vom Deutschen Wetterdienst ein binäres Datenpaket vom Datentype bytes. Dieses konvertieren wir mit der Funktion loads aus dem json Paket in ein Python dict. Um das schöner lesbar auszugeben, nutzen wir die Funktion pprint aus dem Paket pprint (pretty-print).

import urllib.request
import json
import pprint

stationID='12495' # Rostock-Hansaviertel
with urllib.request.urlopen(f'https://dwd.api.proxy.bund.dev/v30/stationOverviewExtended?stationIds={stationID}') as f:
    data=f.read() # Dies gibt uns ein binären Datentyp zurück
    wetter=json.loads(data) # Wir konvertieren den binären Datentyp in ein dict
    pprint.pprint(wetter, indent=2, compact=True)
{ '12495': { 'days': [ { 'dayDate': '2025-08-17',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 6,
                         'moonrise': 1755464484000,
                         'moonriseOnThisDay': 1755464484000,
                         'moonset': 1755439776000,
                         'moonsetOnThisDay': 1755439776000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755400811000,
                         'sunriseOnThisDay': 1755400811000,
                         'sunset': 1755452877000,
                         'sunsetOnThisDay': 1755452877000,
                         'sunshine': 32767,
                         'temperatureMax': 218,
                         'temperatureMin': 139,
                         'windDirection': 3210,
                         'windGust': 370,
                         'windSpeed': 185},
                       { 'dayDate': '2025-08-18',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 6,
                         'moonrise': 1755554333000,
                         'moonriseOnThisDay': 1755554333000,
                         'moonset': 1755530459000,
                         'moonsetOnThisDay': 1755530459000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755487306000,
                         'sunriseOnThisDay': 1755487306000,
                         'sunset': 1755539156000,
                         'sunsetOnThisDay': 1755539156000,
                         'sunshine': 32767,
                         'temperatureMax': 204,
                         'temperatureMin': 117,
                         'windDirection': 3380,
                         'windGust': 315,
                         'windSpeed': 130},
                       { 'dayDate': '2025-08-19',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 6,
                         'moonrise': 1755645158000,
                         'moonriseOnThisDay': 1755645158000,
                         'moonset': 1755620045000,
                         'moonsetOnThisDay': 1755620045000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755573801000,
                         'sunriseOnThisDay': 1755573801000,
                         'sunset': 1755625435000,
                         'sunsetOnThisDay': 1755625435000,
                         'sunshine': 32767,
                         'temperatureMax': 229,
                         'temperatureMin': 119,
                         'windDirection': 3020,
                         'windGust': 204,
                         'windSpeed': 93},
                       { 'dayDate': '2025-08-20',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 7,
                         'moonrise': 1755736539000,
                         'moonriseOnThisDay': None,
                         'moonset': 1755708637000,
                         'moonsetOnThisDay': 1755708637000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755660295000,
                         'sunriseOnThisDay': 1755660295000,
                         'sunset': 1755711712000,
                         'sunsetOnThisDay': 1755711712000,
                         'sunshine': 32767,
                         'temperatureMax': 249,
                         'temperatureMin': 130,
                         'windDirection': 2660,
                         'windGust': 278,
                         'windSpeed': 111},
                       { 'dayDate': '2025-08-21',
                         'icon': 3,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 7,
                         'moonrise': 1755736539000,
                         'moonriseOnThisDay': 1755736539000,
                         'moonset': 1755796531000,
                         'moonsetOnThisDay': 1755796531000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755746790000,
                         'sunriseOnThisDay': 1755746790000,
                         'sunset': 1755797989000,
                         'sunsetOnThisDay': 1755797989000,
                         'sunshine': 32767,
                         'temperatureMax': 211,
                         'temperatureMin': 143,
                         'windDirection': 3150,
                         'windGust': 296,
                         'windSpeed': 93},
                       { 'dayDate': '2025-08-22',
                         'icon': 3,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 7,
                         'moonrise': 1755827997000,
                         'moonriseOnThisDay': 1755827997000,
                         'moonset': 1755884001000,
                         'moonsetOnThisDay': 1755884001000,
                         'precipitation': 1,
                         'stationId': None,
                         'sunrise': 1755833285000,
                         'sunriseOnThisDay': 1755833285000,
                         'sunset': 1755884264000,
                         'sunsetOnThisDay': 1755884264000,
                         'sunshine': 32767,
                         'temperatureMax': 198,
                         'temperatureMin': 125,
                         'windDirection': 3260,
                         'windGust': 315,
                         'windSpeed': 130},
                       { 'dayDate': '2025-08-23',
                         'icon': 3,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 0,
                         'moonrise': 1755919307000,
                         'moonriseOnThisDay': 1755919307000,
                         'moonset': 1755971217000,
                         'moonsetOnThisDay': 1755971217000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1755919779000,
                         'sunriseOnThisDay': 1755919779000,
                         'sunset': 1755970539000,
                         'sunsetOnThisDay': 1755970539000,
                         'sunshine': 32767,
                         'temperatureMax': 188,
                         'temperatureMin': 112,
                         'windDirection': 3030,
                         'windGust': 315,
                         'windSpeed': 148},
                       { 'dayDate': '2025-08-24',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 0,
                         'moonrise': 1756010376000,
                         'moonriseOnThisDay': 1756010376000,
                         'moonset': 1756058291000,
                         'moonsetOnThisDay': 1756058291000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1756006274000,
                         'sunriseOnThisDay': 1756006274000,
                         'sunset': 1756056812000,
                         'sunsetOnThisDay': 1756056812000,
                         'sunshine': 32767,
                         'temperatureMax': 183,
                         'temperatureMin': 102,
                         'windDirection': 3010,
                         'windGust': 296,
                         'windSpeed': 111},
                       { 'dayDate': '2025-08-25',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 0,
                         'moonrise': 1756101241000,
                         'moonriseOnThisDay': 1756101241000,
                         'moonset': 1756145313000,
                         'moonsetOnThisDay': 1756145313000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1756092768000,
                         'sunriseOnThisDay': 1756092768000,
                         'sunset': 1756143084000,
                         'sunsetOnThisDay': 1756143084000,
                         'sunshine': 32767,
                         'temperatureMax': 192,
                         'temperatureMin': 104,
                         'windDirection': 2810,
                         'windGust': 315,
                         'windSpeed': 111},
                       { 'dayDate': '2025-08-26',
                         'icon': 2,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 0,
                         'moonrise': 1756191992000,
                         'moonriseOnThisDay': 1756191992000,
                         'moonset': 1756232335000,
                         'moonsetOnThisDay': 1756232335000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1756179263000,
                         'sunriseOnThisDay': 1756179263000,
                         'sunset': 1756229356000,
                         'sunsetOnThisDay': 1756229356000,
                         'sunshine': 32767,
                         'temperatureMax': 199,
                         'temperatureMin': 112,
                         'windDirection': 2690,
                         'windGust': 333,
                         'windSpeed': 130}],
             'forecast1': { 'cloudCoverTotal': [],
                            'dewPoint2m': [ 100, 94, 89, 87, 85, 85, 86, 86, 87,
                                            89, 90, 90, 89, 88, 88, 88, 87, 88,
                                            94, 101, 105, 107, 105, 105, 102,
                                            101, 100, 100, 98, 99, 100, 102,
                                            105, 106, 106, 107, 106, 108, 107,
                                            107, 107, 108, 113, 119, 125, 124,
                                            121, 117, 114, 112, 111, 109, 107,
                                            109, 112, 116, 116, 118, 118, 121,
                                            119],
                            'humidity': [ 500, 475, 442, 434, 425, 428, 444,
                                          475, 535, 600, 644, 682, 709, 737,
                                          766, 792, 818, 824, 841, 820, 774,
                                          731, 672, 631, 588, 559, 535, 529,
                                          509, 509, 532, 574, 639, 712, 769,
                                          816, 837, 871, 894, 912, 924, 918,
                                          906, 855, 792, 694, 619, 560, 536,
                                          510, 491, 482, 461, 473, 503, 560,
                                          622, 706, 766, 823, 833],
                            'icon': [ 32767, 1, 32767, 32767, 32767, 32767,
                                      32767, 2, 32767, 32767, 32767, 32767, 3,
                                      3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,
                                      1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
                                      2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                                      1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                                      2, 2, 1, 1],
                            'icon1h': [ 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
                                        1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3,
                                        3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
                                        1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
                                        2, 2, 2, 2, 2, 2, 2, 1, 1],
                            'isDay': [ False, False, False, False, False, False,
                                       False, True, False, False, False, False,
                                       True, True, True, True, True, True, True,
                                       True, True, False, False, False, False,
                                       False, False, False, False, False, True,
                                       True, True, True, True, True, True, True,
                                       True, True, True, True, True, True, True,
                                       False, False, False, False, False, False,
                                       False, False, False, True, True, True,
                                       True, True, True, True, True, True, True,
                                       True, True, True, True, True, False,
                                       False, False, False],
                            'precipitationProbablity': None,
                            'precipitationProbablityIndex': None,
                            'precipitationTotal': [ 32767, 32767, 32767, 32767,
                                                    32767, 32767, 32767, 32767,
                                                    32767, 32767, 32767, 32767,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0],
                            'start': 1755381600000,
                            'stationId': '12495',
                            'sunshine': [ 32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767],
                            'surfacePressure': [ 10140, 10137, 10133, 10132,
                                                 10131, 10131, 10132, 10136,
                                                 10142, 10147, 10152, 10155,
                                                 10159, 10161, 10162, 10165,
                                                 10167, 10169, 10174, 10176,
                                                 10178, 10181, 10181, 10182,
                                                 10183, 10183, 10183, 10182,
                                                 10182, 10182, 10182, 10183,
                                                 10186, 10187, 10189, 10192,
                                                 10192, 10192, 10191, 10190,
                                                 10187, 10186, 10185, 10184,
                                                 10182, 10180, 10178, 10175,
                                                 10174, 10167, 10161, 10156,
                                                 10149, 10146, 10142, 10138,
                                                 10139, 10137, 10136, 10133,
                                                 10132],
                            'temperature': [ 32767, 32767, 176, 32767, 32767,
                                             32767, 32767, 32767, 170, 32767,
                                             32767, 32767, 32767, 208, 210, 216,
                                             217, 218, 217, 212, 201, 183, 167,
                                             157, 148, 141, 134, 128, 123, 117,
                                             117, 120, 131, 144, 155, 166, 176,
                                             184, 191, 197, 199, 203, 204, 198,
                                             188, 174, 158, 146, 138, 133, 129,
                                             124, 121, 119, 121, 128, 143, 161,
                                             181, 196, 208, 212, 218, 223, 224,
                                             229, 227, 220, 207, 190, 172, 159,
                                             151, 147, 142, 137, 134, 130, 130,
                                             139, 154, 174, 193, 210, 223, 232,
                                             238, 247, 248, 249, 242, 234, 221,
                                             204, 186, 176, 168, 162, 156, 152,
                                             147, 144, 143, 145, 150, 163, 177,
                                             186, 197, 205, 210, 211, 210, 206,
                                             200, 193, 185, 176, 172, 162, 158,
                                             153, 150, 143, 139, 136, 133, 133,
                                             140, 148, 157, 168, 178, 186, 192,
                                             196, 198, 198, 195, 189, 176, 163,
                                             151, 140, 131, 125, 121, 117, 115,
                                             112, 113, 118, 126, 138, 152, 166,
                                             175, 179, 182, 187, 188, 188, 186,
                                             181, 170, 151, 138, 128, 120, 114,
                                             111, 106, 105, 102, 102, 107, 116,
                                             131, 143, 157, 166, 173, 176, 182,
                                             183, 183, 182, 177, 168, 151, 141,
                                             129, 124, 116, 112, 108, 106, 104,
                                             105, 110, 117, 129, 144, 158, 166,
                                             176, 183, 187, 189, 192, 190, 185,
                                             174, 156, 150, 141, 134, 131, 122,
                                             118, 115, 113, 112, 117, 125, 139,
                                             154, 168, 178, 186, 193, 199, 198,
                                             196, 192, 192, 181, 164, 157, 148,
                                             142, 137],
                            'temperatureStd': [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                0, 0, 9, 9, 11, 12, 11, 11, 12,
                                                11, 9, 10, 12, 12, 12, 11, 12,
                                                11, 12, 14, 12, 9, 9, 9, 10, 11,
                                                12, 12, 12, 12, 12, 10, 12, 12,
                                                12, 12, 12, 12, 12, 11, 12, 13,
                                                14, 15, 14, 12, 10, 12, 12, 9,
                                                9, 9, 9, 9, 9, 10, 11, 12, 14,
                                                13, 14, 14, 14, 14, 14, 14, 14,
                                                14, 15, 12, 11, 12, 14, 14, 14,
                                                15, 16, 16, 16, 17, 17, 16, 15,
                                                14, 14, 15, 14, 14, 14, 12, 14,
                                                15, 15, 14, 14, 16, 18, 19, 21,
                                                22, 22, 21, 22, 22, 21, 20, 18,
                                                18, 16, 16, 18, 18, 19, 19, 18,
                                                18, 18, 16, 15, 17, 19, 20, 19,
                                                20, 21, 21, 20, 20, 19, 19, 18,
                                                17, 16, 15, 16, 16, 17, 16, 17,
                                                18, 18, 16, 15, 15, 15, 13, 13,
                                                14, 15, 15, 14, 16, 16, 17, 16,
                                                17, 17, 17, 18, 18, 18, 18, 18,
                                                18, 17, 16, 19, 19, 18, 19, 20,
                                                21, 20, 20, 22, 21, 21, 20, 20,
                                                20, 20, 20, 19, 20, 19, 19, 19,
                                                19, 19, 20, 19, 19, 20, 21, 22,
                                                23, 22, 23, 23, 23, 22, 21, 21,
                                                21, 20, 20, 20, 22, 22, 22, 22,
                                                20, 20, 19, 17, 18, 19, 21, 22,
                                                22, 22, 21, 21, 22, 22, 20, 20,
                                                20, 20, 20, 20],
                            'timeStep': 3600000,
                            'windDirection': None,
                            'windGust': None,
                            'windSpeed': None},
             'forecast2': { 'cloudCoverTotal': [],
                            'dewPoint2m': [ 117, 119, 125, 112, 108, 111, 119,
                                            117, 112, 114, 123, 119, 117, 122,
                                            122, 117, 113, 109, 108, 95, 82, 85,
                                            87, 85, 82, 87, 95, 87, 79, 80, 83,
                                            80, 79, 84, 91, 88, 77, 81, 88, 83,
                                            84, 88, 95, 87, 80, 82, 87, 88, 87,
                                            94, 107, 102, 101, 105, 106, 106],
                            'humidity': [ 895, 877, 648, 468, 414, 459, 650,
                                          747, 795, 817, 707, 578, 553, 635,
                                          724, 791, 843, 854, 726, 554, 471,
                                          509, 656, 766, 802, 813, 688, 549,
                                          491, 517, 694, 796, 839, 857, 709,
                                          574, 500, 534, 704, 802, 863, 863,
                                          724, 559, 492, 511, 660, 752, 829,
                                          858, 736, 581, 536, 571, 717, 816],
                            'icon': [ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
                                      3, 3, 3, 19, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3,
                                      3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2,
                                      2, 2, 3, 3, 2, 2, 2, 2, 3, 2, 3, 2, 2,
                                      2],
                            'icon1h': [ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
                                        3, 3, 3, 3, 19, 3, 3, 3, 3, 2, 2, 2, 3,
                                        3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2,
                                        2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 3, 2,
                                        3, 2, 2, 2],
                            'isDay': [ False, False, True, True, True, True,
                                       True, False, False, False, True, True,
                                       True, True, True, False, False, False,
                                       True, True, True, True, True, False,
                                       False, False, True, True, True, True,
                                       True, False, False, False, True, True,
                                       True, True, True, False, False, False,
                                       True, True, True, True, True, False,
                                       False, False, True, True, True, True,
                                       False, False],
                            'precipitationProbablity': None,
                            'precipitationProbablityIndex': None,
                            'precipitationTotal': [ 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 1,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0],
                            'start': 1755640800000,
                            'stationId': '12495',
                            'sunshine': [ 32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767],
                            'surfacePressure': [ 10122, 10112, 10099, 10088,
                                                 10080, 10073, 10084, 10090,
                                                 10086, 10081, 10077, 10076,
                                                 10073, 10071, 10075, 10074,
                                                 10072, 10073, 10084, 10094,
                                                 10098, 10099, 10116, 10120,
                                                 10122, 10121, 10125, 10126,
                                                 10118, 10130, 10144, 10152,
                                                 10150, 10155, 10154, 10149,
                                                 10141, 10143, 10154, 10157,
                                                 10151, 10150, 10150, 10148,
                                                 10142, 10143, 10156, 10155,
                                                 10153, 10155, 10159, 10154,
                                                 10144, 10146, 10147, 10150],
                            'temperature': [],
                            'temperatureStd': [],
                            'timeStep': 10800000,
                            'windDirection': None,
                            'windGust': None,
                            'windSpeed': None},
             'forecastStart': None,
             'threeHourSummaries': None,
             'warnings': []}}

Externe Pakete installieren und importieren#

Die Stärke von Python ist allerdings die riesige Auswahl an vorhandenen Paketen. Für die meisten Anwendungszwecke gibt es entsprechende Python Packages. Ein solches Verzeichnis is PyPi das über 400.000 Pakete listet.

Die Installation neuer Pakete für Python ist einfach. Hierfür öffnet man ein Terminal (Kommandozeile) und gibt den Befehl pip install <packetname> ein.

Zum Beispiel wollen wir die eben geladenen Wetterdaten anzeigen. Hierfür nutzen wir:

  • zuerst das Paket pandas zum Erzeugen einer Tabelle aus den Wetterdaten.

  • dann nutzen wir das Paket plotly zum Zeichnen eines Diagramms.

  • zuletzt erzeugen wir uns einen Webserver mit dash der uns das Diagramm immer anzeigt

Alles drei installieren wir mit pip. Wir können das in einem Aufruf machen. Wir nutzen den --quiet Switch, um die Ausgabe zu reduzieren.

pip install pandas plotly dash  --quiet
/Users/jplonnigs/.zshenv:.:1: no such file or directory: /Users/jplonnigs/.cargo/env
/Users/jplonnigs/Documents/code/Lehre/ProgrammierUebung/.venv/bin/python: No module named pip
Note: you may need to restart the kernel to use updated packages.

Jetzt laden wir beide Pakete, wobei man üblicher Weise pandas die Abkürzung pd zuweist und Plotly Express, welches einfach zu bedienen ist, die Abkürzung px.

import pandas as pd
import plotly.express as px
import dash

Nun wandeln wir die tageweise Wettervorhersage days der Daten von der Wetterstation mit der stationID zuerst in eine Tabelle um, da diese von Plotly express verarbeitet werden kann. Tabellen heißen in Pandas DataFrames (allgemein werden so Tabellen in der Data Science genannt). Wir erzeugen also aus der Wettervorhersage ein neue Objektinstanz vom Typ DataFrame via

df = pd.DataFrame(wetter[stationID]['days'])
df
stationId dayDate temperatureMin temperatureMax precipitation windSpeed windGust windDirection sunshine sunrise ... moonrise moonset moonriseOnThisDay moonsetOnThisDay sunriseOnThisDay sunsetOnThisDay moonPhase icon icon1 icon2
0 None 2025-08-17 139 218 0 185 370 3210 32767 1755400811000 ... 1755464484000 1755439776000 1.755464e+12 1755439776000 1755400811000 1755452877000 6 2 None None
1 None 2025-08-18 117 204 0 130 315 3380 32767 1755487306000 ... 1755554333000 1755530459000 1.755554e+12 1755530459000 1755487306000 1755539156000 6 2 None None
2 None 2025-08-19 119 229 0 93 204 3020 32767 1755573801000 ... 1755645158000 1755620045000 1.755645e+12 1755620045000 1755573801000 1755625435000 6 2 None None
3 None 2025-08-20 130 249 0 111 278 2660 32767 1755660295000 ... 1755736539000 1755708637000 NaN 1755708637000 1755660295000 1755711712000 7 2 None None
4 None 2025-08-21 143 211 0 93 296 3150 32767 1755746790000 ... 1755736539000 1755796531000 1.755737e+12 1755796531000 1755746790000 1755797989000 7 3 None None
5 None 2025-08-22 125 198 1 130 315 3260 32767 1755833285000 ... 1755827997000 1755884001000 1.755828e+12 1755884001000 1755833285000 1755884264000 7 3 None None
6 None 2025-08-23 112 188 0 148 315 3030 32767 1755919779000 ... 1755919307000 1755971217000 1.755919e+12 1755971217000 1755919779000 1755970539000 0 3 None None
7 None 2025-08-24 102 183 0 111 296 3010 32767 1756006274000 ... 1756010376000 1756058291000 1.756010e+12 1756058291000 1756006274000 1756056812000 0 2 None None
8 None 2025-08-25 104 192 0 111 315 2810 32767 1756092768000 ... 1756101241000 1756145313000 1.756101e+12 1756145313000 1756092768000 1756143084000 0 2 None None
9 None 2025-08-26 112 199 0 130 333 2690 32767 1756179263000 ... 1756191992000 1756232335000 1.756192e+12 1756232335000 1756179263000 1756229356000 0 2 None None

10 rows × 21 columns

Nun plotten wir die Daten df als LinienDiagramm mit Hilfe von Plotly wobei wir als x-Axe das Datum wählen (dayDate) und als y-Axe die minimale Temperatur temperatureMin und maximale Temperatur temperatureMax.

fig=px.line(df, x="dayDate", y=["temperatureMin", "temperatureMax"])
fig.show(renderer="svg")
../_images/ac3fdf7de48079d154cc2c4c2104109f313ac21f8143982d280ffa7365777415.svg

Zuletzt wollen wir dieses Diagramm in einer Webseite auf einem Webserver anzeigen. Hier nutzen wir das Paket dash welches erlaubt eine Webseite mit Python-Befehlen zu erzeugen und darin interaktive Diagramme von Plotly mit anzuzeigen.

import dash

app = dash.Dash()

Dann erzeugen wir eine Webseite mit einer Überschrift (H1), welche den Plot als Graph enthält.

app.layout = dash.html.Div(children = [
    dash.html.H1(children='Wetter in Rostock'),
    dash.dcc.Graph(id="fare_vs_age", figure=fig)
])

Und starten den Webserver.

app.run_server()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[16], line 1
----> 1 app.run_server()

File ~/Documents/code/Lehre/ProgrammierUebung/.venv/lib/python3.12/site-packages/jupyter_dash/jupyter_app.py:176, in JupyterDash.run_server(self, mode, width, height, inline_exceptions, **kwargs)
    154 """
    155 Serve the app using flask in a background thread. You should not run this on a
    156 production server, use gunicorn/waitress instead.
   (...)    173     ``Dash.run_server`` method.
    174 """
    175 # Get superclass run_server method
--> 176 super_run_server = super(JupyterDash, self).run_server
    178 if not JupyterDash._in_ipython:
    179     # If not in IPython context, call run run_server synchronously
    180     super_run_server(**kwargs)

AttributeError: 'super' object has no attribute 'run_server'

Dies startet einen Webserver auf den wir in einem Browser unter http://127.0.0.1:8083/ zugreifen können. Er zeigt uns eine Webseite mit einem interaktiven Diagramm welches die Wetterdaten anzeigt.