Python Leistungsbeurteilung

Von: Riccardo Ambühl
Datum: 26.06.2025

Übersicht

Da ich die in den Modulen Berechnung der Kündigungsfrist und Rekonstruktion der Mittelflussrechnung behandelten Funktionen und Logiken sicher beherrsche, dokumentiere ich im Folgenden, was ich im Detail gelernt habe und wie ich dieses Wissen im Alltag anwenden kann.

Inhalt:

Verwendete Technologien:

Python 3.13.3 datetime holidays pandas tabulate

Kündigungsfrist im Mietrecht mit Python

Diese Funktionen unterstützen die Berechnung und Prüfung von Fristen im Mietrecht. Es werden u.a. Wochenenden, Feiertage sowie Fristen für die Kündigungszustellung berücksichtigt.

kuendigung.py
import datetime

def get_weekday(datum: datetime.date) -> bool:
    return datum.weekday()

beispieldatum = datetime.date(2020, 1, 2)
wochentage = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']

wochentag = get_weekday(beispieldatum)
wochentag = wochentage[wochentag]
print(wochentag)
> Donnerstag

Wochentag berechnen

Nimmt ein Datum und gibt den Wochentag als Zahl (0=Montag, ..., 6=Sonntag) zurück.

kuendigung.py
import holidays
import datetime

def is_holiday(datum: datetime.date) -> bool:
    feiertage = holidays.Switzerland(subdiv='ZH')
    return datum in feiertage

print(is_holiday(datetime.date(2025, 5, 1)))
print(is_holiday(datetime.date(2025, 5, 2)))
> True
> False

Feiertagserkennung (ZH)

Prüft, ob ein gegebenes Datum im Kanton Zürich ein Feiertag ist. Sie gibt True oder False zurück.

kuendigung.py
import datetime

def is_weekend(datum: datetime.date) -> bool:
    return datum.weekday() > 4

print(is_weekend(datetime.date(2025, 5, 20)))
> False

Wochenenderkennung

Überprüft, ob ein Datum am Wochenende liegt.

kuendigung.py
import datetime

def get_zustelldatum(abgabedatum: datetime.date) -> datetime.date:
    zustelldatum = abgabedatum + datetime.timedelta(days=1)

    while is_weekend(zustelldatum) or is_holiday(zustelldatum):
        zustelldatum += datetime.timedelta(days=1)
        
    return zustelldatum

print(get_zustelldatum(datetime.date(2025, 5, 16)))
> 2025-05-19

Zustelldatum berechnen

Berechnet das Zustelldatum eines Briefs, indem es das Wochenende und Feiertage berücksichtigt. Der nächste gültige Werktag wird zurückgegeben.

kuendigung.py
import datetime

def get_abgabedatum(zustelldatum: datetime.date) -> datetime.date:
    abgabedatum = zustelldatum - datetime.timedelta(days=1)

    while is_weekend(abgabedatum) or is_holiday(abgabedatum):
        abgabedatum -= datetime.timedelta(days=1)
        
    return abgabedatum

print(get_abgabedatum(datetime.date(2025, 5, 19)))
> 2025-05-16

Abgabedatum berechnen

Ermittelt das späteste mögliche Abgabedatum, damit ein Brief an einem gewünschten Werktag zugestellt wird.

kuendigung.py
import datetime

def set_kuendigungstermine(referenzdatum: datetime.date) -> list:
    year = referenzdatum.year + 1 if referenzdatum.month >= 6 else referenzdatum.year
    return [
        datetime.date(year, 3, 31),
        datetime.date(year, 6, 30),
        datetime.date(year, 9, 30)
    ]

print(set_kuendigungstermine(datetime.date(2025, 7, 20)))
> [datetime.date(2026, 3, 31), datetime.date(2026, 6, 30), datetime.date(2026, 9, 30)]

Kündigungstermine setzen

Die Funktion liefert die möglichen Kündigungstermine, basierend auf einem Referenzdatum.

kuendigung.py
import datetime

def get_kuendigungstermin(aufgabedatum: datetime.date) -> datetime.date:
    zustellung = get_zustelldatum(aufgabedatum)
    
    kuendigungstermine = set_kuendigungstermine(aufgabedatum)

    monat = zustellung.month + 3
    jahr = zustellung.year

    if monat > 12:
        monat -= 12
        jahr += 1
    
    termin = datetime.date(jahr, monat, zustellung.day)
    
    if termin < kuendigungstermine[0]:
        return kuendigungstermine[0]
    elif termin < kuendigungstermine[1]:
        return kuendigungstermine[1]
    else:
        return kuendigungstermine[2]
    
print(get_kuendigungstermin(datetime.date(2024, 12, 1)))
> 2025-03-31

Kündigungstermin ermitteln

Berechnet den nächstmöglichen Kündigungstermin unter Berücksichtigung einer Zustellung + 3 Monate Frist.

kuendigung.py
import datetime

def get_aufgabedatum(kuendigungstermin: datetime.date) -> datetime.date:
    monat = kuendigungstermin.month - 3
    jahr = kuendigungstermin.year

    if monat <= 0:
        monat += 12
        jahr -= 1

    rueckdatum = get_abgabedatum(
        datetime.date(
            jahr,
            monat,
            kuendigungstermin.day
        )
    )
        
    return rueckdatum

print(get_aufgabedatum(datetime.date(2025, 1, 19)))
> 2024-10-18

Aufgabedatum bestimmen

Bestimmt das letztmögliche Aufgabedatum für einen Kündigungstermin unter Einhaltung der dreimonatigen Frist.

Berechnung des Cash Flows

In diesem Abschnitt wird die indirekte Berechnung des Cash Flows gezeigt – anhand von Bilanz- und Jahresabschlussdaten.

cashflow.py
import pandas as pd

bilanz = pd.read_csv('beispieldaten-1.csv', index_col=0)
liquide_mittel = bilanz.loc[1000:1020, 'Betrag'].sum()
print(liquide_mittel)
> 25

Liquide Mittel berechnen

Liest die Bilanzdaten ein und summiert die Konten von 1000 bis 1020. Das ergibt die gesamten liquiden Mittel.

cashflow.py
jahresabschluss = pd.read_csv('beispieldaten-2.csv', index_col=0, dtype={'Eroeffnung': 'Int64'})
veraenderung_liquide_mittel = jahresabschluss.loc[1000:1020, 'Abschluss'].sum() - jahresabschluss.loc[1000:1020, 'Eroeffnung'].sum()
print(veraenderung_liquide_mittel)
> 40

Veränderung der liquiden Mittel

Berechnet die Differenz der liquiden Mittel zwischen Eröffnung und Abschluss der Konten 1000–1020.

cashflow.py
positionen = {}

positionen["Jahresgewinn"] = jahresabschluss.loc[3000:8900]['Abschluss'].sum()
positionen["Abschreibungen"] = jahresabschluss.loc[6800:6899]['Abschluss'].sum() * -1
positionen["Rückstellungen"] = (
    (jahresabschluss.loc[2330:2399]['Abschluss'].sum() + jahresabschluss.loc[2600:2799]['Abschluss'].sum()) -
    (jahresabschluss.loc[2330:2399]['Eroeffnung'].sum() + jahresabschluss.loc[2600:2799]['Eroeffnung'].sum())
) * -1
positionen["Liquide WS"] = jahresabschluss.loc[1060:1069]['Eroeffnung'].sum() - jahresabschluss.loc[1060:1069]['Abschluss'].sum()
positionen["Veränderung FLL"] = jahresabschluss.loc[1100:1109]['Eroeffnung'].sum() - jahresabschluss.loc[1100:1109]['Abschluss'].sum()
positionen["Veränderung übrige kf Forderungen"] = jahresabschluss.loc[1140:1199]['Eroeffnung'].sum() - jahresabschluss.loc[1140:1199]['Abschluss'].sum()
positionen["Veränderung Vorräte"] = jahresabschluss.loc[1200:1299]['Eroeffnung'].sum() - jahresabschluss.loc[1200:1299]['Abschluss'].sum()
positionen["Veränderung ARA"] = jahresabschluss.loc[1300:1399]['Eroeffnung'].sum() - jahresabschluss.loc[1300:1399]['Abschluss'].sum()
positionen["Veränderung VLL"] = jahresabschluss.loc[2000:2099]['Abschluss'].sum() - jahresabschluss.loc[2000:2099]['Eroeffnung'].sum()
positionen["Veränderung übrige Verbindlichkeiten"] = (
    (jahresabschluss.loc[2200:2210]['Abschluss'].sum() - jahresabschluss.loc[2200:2210]['Eroeffnung'].sum()) +
    (jahresabschluss.loc[2270:2279]['Abschluss'].sum() - jahresabschluss.loc[2270:2279]['Eroeffnung'].sum())
)
positionen["Veränderung PRA"] = jahresabschluss.loc[2300:2399]['Abschluss'].sum() - jahresabschluss.loc[2300:2399]['Eroeffnung'].sum()
positionen["Veränderung übriger Fondsfremder Erfolg"] = (
    jahresabschluss.loc[8000:8999]['Abschluss'].sum() - jahresabschluss.loc[8000:8999]['Eroeffnung'].sum()
) * -1

Cash Flow Positionen berechnen

Hier werden alle Positionen für die indirekte Geldflussrechnung anhand von Kontoänderungen im Jahresabschluss berechnet.

cashflow.py
print(f'Jahresgewinn: {positionen["Jahresgewinn"]}')
print(f'Abschreibungen: {positionen["Abschreibungen"]}')
print(f'Rückstellungen: {positionen["Rückstellungen"]}')
print(f'FLL: {positionen["Veränderung FLL"]}')
print(f'KF-Forderungen: {positionen["Veränderung übrige kf Forderungen"]}')
print(f'Liquide WS: {positionen["Liquide WS"]}')
print(f'Vorräte: {positionen["Veränderung Vorräte"]}')
print(f'ARA: {positionen["Veränderung ARA"]}')
print(f'VLL: {positionen["Veränderung VLL"]}')
print(f'Übrige Verbindlichkeiten: {positionen["Veränderung übrige Verbindlichkeiten"]}')
print(f'PRA: {positionen["Veränderung PRA"]}')
print(f'Rest: {positionen["Veränderung übriger Fondsfremder Erfolg"]}')
print(f'Cash Flow: {sum(positionen.values())}')
> Jahresgewinn: 18
> Abschreibungen: 15
> Rückstellungen: 0
> FLL: -14
> KF-Forderungen: 0
> Liquide WS: 0
> Vorräte: 15
> ARA: 0
> VLL: -12
> Übrige Verbindlichkeiten: 0
> PRA: 1
> Rest: 0
> Cash Flow: 23

Cash Flow Ausgabe (Einzeln)

Die Werte aus den Positionen werden ausgegeben – darunter der finale berechnete Cash Flow.

cashflow.py
from tabulate import tabulate

def cash_flow(ledger: pd.DataFrame) -> None:
    positionen = {}

    positionen["Jahresgewinn"] = ledger.loc[3000:8900]['Abschluss'].sum()
    positionen["Abschreibungen"] = ledger.loc[6800:6899]['Abschluss'].sum() * -1
    positionen["Rückstellungen"] = (
        (ledger.loc[2330:2399]['Abschluss'].sum() + ledger.loc[2600:2799]['Abschluss'].sum()) -
        (ledger.loc[2330:2399]['Eroeffnung'].sum() + ledger.loc[2600:2799]['Eroeffnung'].sum())
    ) * -1
    positionen["Liquide WS"] = ledger.loc[1060:1069]['Eroeffnung'].sum() - ledger.loc[1060:1069]['Abschluss'].sum()
    positionen["Veränderung FLL"] = ledger.loc[1100:1109]['Eroeffnung'].sum() - ledger.loc[1100:1109]['Abschluss'].sum()
    positionen["Veränderung übrige kf Forderungen"] = ledger.loc[1140:1199]['Eroeffnung'].sum() - ledger.loc[1140:1199]['Abschluss'].sum()
    positionen["Veränderung Vorräte"] = ledger.loc[1200:1299]['Eroeffnung'].sum() - ledger.loc[1200:1299]['Abschluss'].sum()
    positionen["Veränderung ARA"] = ledger.loc[1300:1399]['Eroeffnung'].sum() - ledger.loc[1300:1399]['Abschluss'].sum()
    positionen["Veränderung VLL"] = ledger.loc[2000:2099]['Abschluss'].sum() - ledger.loc[2000:2099]['Eroeffnung'].sum()
    positionen["Veränderung übrige Verbindlichkeiten"] = (
        (ledger.loc[2200:2210]['Abschluss'].sum() - ledger.loc[2200:2210]['Eroeffnung'].sum()) +
        (ledger.loc[2270:2279]['Abschluss'].sum() - ledger.loc[2270:2279]['Eroeffnung'].sum())
    )
    positionen["Veränderung PRA"] = ledger.loc[2300:2399]['Abschluss'].sum() - ledger.loc[2300:2399]['Eroeffnung'].sum()
    positionen["Veränderung übriger Fondsfremder Erfolg"] = (
        ledger.loc[8000:8999]['Abschluss'].sum() - ledger.loc[8000:8999]['Eroeffnung'].sum()
    ) * -1

    gesamt_cashflow = sum(positionen.values())

    table = [[key, f"{value:,.2f} CHF"] for key, value in positionen.items() if value != 0]
    table.append(["Gesamt Cash Flow", f"{gesamt_cashflow:,.2f} CHF"])

    print("Indirekte Geldflussrechnung\n")
    print(tabulate(table, headers=["Position", "Betrag"], tablefmt="github"))
  
cash_flow(jahresabschluss)
> Indirekte Geldflussrechnung

> | Position | Betrag |
|---------------------|------------|
| Jahresgewinn | 18.00 CHF |
| Abschreibungen | 15.00 CHF |
| Veränderung FLL | -14.00 CHF |
| Veränderung Vorräte | 15.00 CHF |
| Veränderung VLL | -12.00 CHF |
| Veränderung PRA | 1.00 CHF |
| Gesamt Cash Flow | 23.00 CHF |

Funktion zur Geldflussrechnung

Die Funktion gibt eine formatierte Übersicht über alle Cash Flow Positionen und den Gesamtwert aus. Tabulate hilft bei der Darstellung der Daten.

Mittelfluss aus Investitionen

Diese Funktionen analysieren die Investitionstätigkeit eines Unternehmens – aufgeteilt nach Mobilien und Immobilien.

investitionen.py
import pandas as pd
from typing import Iterable
jahresabschluss = pd.read_csv('beispieldaten-2.csv', index_col=0)

Importe & Laden der Daten

Die notwendigen Module werden importiert. Anschliessend wird die CSV-Datei mit dem Jahresabschluss eingelesen. Iterable hilft, Typen präzise anzugeben und macht den Code übersichtlicher.

investitionen.py
def _check_konto(ledger: pd.DataFrame, konti: Iterable[int]) -> bool:
    return any(konto in ledger.index for konto in konti)

Helferfunktion: Kontenprüfung

Prüft, ob ein bestimmter Satz an Kontonummern im gegebenen Jahresabschluss enthalten ist.

investitionen.py
def _get_total_absch(ledger: pd.DataFrame) -> float:
    konti = (ledger.index >= 6800) & (ledger.index < 6900)
    total_absch = ledger.loc[konti, 'Abschluss'].sum() * -1
    return total_absch

Helferfunktion: Total Abschreibungen

Berechnet die gesamten Abschreibungen aus den Konten 6800–6899 im Abschluss.

investitionen.py
def _check_wb_mob(ledger: pd.DataFrame) -> bool:
    return _check_konto(ledger, [1509, 1519, 1529, 1539, 1549])

def _check_wb_immo(ledger: pd.DataFrame) -> bool:
    return _check_konto(ledger, [1609])

Prüfung: WB Mobilien & Immobilien

Diese Funktionen prüfen, ob Wertberichtigungskonten für Mobilien bzw. Immobilien im Jahresabschluss enthalten sind.

investitionen.py
def _get_delta_wb_mob(ledger: pd.DataFrame) -> float:
    konti = ledger.index.intersection([1509, 1519, 1529, 1539, 1549])
    if konti.empty:
        return 0
    return (ledger.loc[konti, 'Abschluss'].sum() - ledger.loc[konti, 'Eroeffnung'].sum()) * -1

def _get_delta_wb_immo(ledger: pd.DataFrame) -> float:
    if _check_wb_immo(ledger):
        return (ledger.loc[1609, 'Abschluss'] - ledger.loc[1609, 'Eroeffnung']) * -1
    return 0

Delta WB Mobilien & Immobilien

Berechnet die Veränderung der Wertberichtigungen auf Mobilien und Immobilien als Teil der Investitionsrechnung.

investitionen.py
def _get_absch_mob(ledger: pd.DataFrame) -> float:
    absch = _get_total_absch(ledger)
    if _check_wb_mob(ledger):
        return _get_delta_wb_mob(ledger)
    delta_wb_immo = _get_delta_wb_immo(ledger)
    if delta_wb_immo < 0:
        return absch
    return absch - delta_wb_immo

def _get_absch_immo(ledger: pd.DataFrame) -> float:
    if _check_wb_immo(ledger):
        return _get_delta_wb_immo(ledger)
    return _get_total_absch(ledger) + _get_absch_mob(ledger)

Abschreibungen auf Mobilien & Immobilien

Berechnung der Abschreibungen für Mobilien und Immobilien – abhängig davon, ob direkt oder über Wertberichtigungen gebucht wurde.

investitionen.py
def _get_invest_mob(ledger: pd.DataFrame) -> float:
    konti = ledger.index.intersection([1500, 1510, 1520, 1530, 1540])
    invest_mob = (ledger.loc[konti, 'Abschluss'] - ledger.loc[konti, 'Eroeffnung']).sum()
    if not _check_wb_mob(ledger):
        invest_mob += _get_absch_mob(ledger)
    return invest_mob

def _get_invest_immo(ledger: pd.DataFrame) -> float:
    detla_immo = ledger.loc[1600, 'Abschluss'] - ledger.loc[1600, 'Eroeffnung']
    absch_immo = _get_absch_immo(ledger)
    if detla_immo * -1 == absch_immo:
        return 0
    return detla_immo + absch_immo

Investitionen berechnen (Mobilien & Immobilien)

Diese Funktionen berechnen die Nettoinvestitionen in Mobilien und Immobilien aus dem Jahresabschluss.

investitionen.py
from tabulate import tabulate

def investitionsbereich(ledger: pd.DataFrame):
    positionen = {
        'Mobilien': _get_invest_mob(ledger),
        'Immobilien': _get_invest_immo(ledger),
    }
    nettoinvestitionen = positionen['Mobilien'] + positionen['Immobilien']
    table = [[key, f"{value:,.2f} CHF"] for key, value in positionen.items() if value != 0]
    table.append(["Nettoinvestitionen", f"{nettoinvestitionen:,.2f} CHF"])
    print('Mittelfluss aus Investitionen\\n')
    print(tabulate(table, headers=['Position', 'Betrag'], tablefmt='github'))

investitionsbereich(jahresabschluss)
> Mittelfluss aus Investitionen

> | Position | Betrag |
|--------------------|-----------|
| Mobilien | 20.00 CHF |
| Immobilien | 10.00 CHF |
| Nettoinvestitionen | 30.00 CHF |

Gesamtauswertung & Ausgabe

Die Gesamtsumme der Investitionen wird hier in einer Tabelle angezeigt – unterteilt in Mobilien und Immobilien. Tabulate hilft auch hier bei der Angabe der Daten.

Abschluss & Hinweise

Allgemein kann ich sagen, dass ich sowohl die technologischen als auch die buchhalterischen Aspekte dieser Arbeit verstanden habe. Ich hätte keine Schwierigkeiten, den Code neu zu programmieren oder in komplexeren Projekten wiederzuverwenden, mithilfe meiner Notizen und der dokumentierten Syntax. In der Praxis lassen sich die erlernten Inhalte gut anwenden, zum Beispiel wenn man später in einem Unternehmen im Bereich Buchhaltung tätig ist und Arbeitsprozesse automatisieren möchte, oder auch, wenn man ein eigenes Unternehmen führt. Dennoch ist die Welt der Finanzen weitaus umfangreicher, und es gibt viele Möglichkeiten, das Projekt weiter auszubauen, beispielsweise durch zusätzliche Funktionen oder den Einsatz neuer Technologien, wie zum Beispiel eine automatisierte Abschreibungenberechnung, die Abschreibungen automatisiert berechnet und den jährlichen Rechenaufwand abnimmt. Ausserdem könnte man die entwickelten Technologien auch kommerziell weiterverwenden, zum Beispiel in Form einer App, in der man Finanzdaten im CSV-Format einliest und daraufhin automatisch eine Bilanz, Erfolgsrechnung sowie Geldflussrechnung generiert.

Erlernte Kentnisse

Während meines Projekts habe ich viele konkrete Dinge gelernt, vor allem im Umgang mit Daten und Datumswerten. Hier sind die wichtigsten Kenntnisse, die ich mir angeeignet habe:

  • Arbeiten mit der datetime-Bibliothek, um mit Datums- und Zeitangaben umzugehen
  • Den Wochentag aus einem Datum bestimmen
  • Die holidays-Bibliothek nutzen, um Feiertage automatisch zu erkennen
  • Prüfen, ob ein bestimmtes Datum ein Feiertag ist
  • Herausfinden, ob ein Datum auf ein Wochenende fällt
  • Datumsangaben in verschiedenen Formaten verarbeiten und umwandeln
  • Beträge aus Datensätzen ermitteln und sinnvoll kombinieren
  • Daten gezielt nach bestimmten Kriterien durchsuchen

Was mir dabei besonders aufgefallen ist: Viele Funktionen in meinem Projekt basieren nicht nur auf einem dieser Punkte allein, sondern auf der Kombination mehrerer dieser Kenntnisse. Zum Beispiel war es oft nötig, gleichzeitig zu prüfen, ob ein Tag ein Wochenende oder Feiertag ist und dann auch die Beträge herauszufiltern war immer gleich, aber das kombinieren hat das Projekt ausgemacht. Das Zusammenspiel dieser Fähigkeiten war also entscheidend, um das Projekt erfolgreich umzusetzen und gar nicht unbedingt viel Wissen. Ein sehr gutes Vorgehen ist immer zuerst die Logik dahinter zu verstehen und es dann zu programmieren, so kann man sehr viel Zeit und Aufwand sparen.

Hinweis zu den Quellen und verwendeten Tools

Das vorliegende Projekt wurde eigenständig auf Grundlage des Unterrichtsskripts sowie eigener Notizen umgesetzt. Zur Unterstützung beim Programmieren kam GitHub Copilot zum Einsatz – ein KI-gestütztes System, das in Visual Studio Code integriert ist und kontextabhängige Vorschläge für Codeergänzungen, Vervollständigungen und Verbesserungen unterbreitet. Die Verwendung von GitHub Copilot erfolgte ausschliesslich zur technischen Unterstützung beim Codieren, insbesondere zur automatischen Vervollständigung bekannter Muster, Strukturen und Syntax. Copilot arbeitet promptfrei, das heisst, es wurden keine aktiven Eingaben oder Chatverläufe zur Generierung von Vorschlägen verwendet. Alle inhaltlichen, konzeptionellen und logischen Entscheidungen wurden eigenständig getroffen. Die KI wurde nicht zur Entwicklung neuer Ideen oder zur Lösung fachlicher Problemstellungen herangezogen. Erstellt mit Hilfe von ChatGPT, OpenAI

Die vollständige Urheberschaft dieses Projekts liegt bei mir (Riccardo Ambühl), soweit nicht anders angegeben. Sämtliche Inhalte, Strukturen und Entscheidungen stammen eigenständig von mir. Drittinhalte (z. B. Icons oder Vorlagen) wurden gemäss ihrer jeweiligen Lizenz eingebunden und entsprechend gekennzeichnet.

Vielen Dank für Ihre Aufmerksamkeit!

© 2025 Riccardo Ambühl

Python Leistungsbeurteilung für Informatik Unterricht