ALG-1 Rechner in Python - Programmstruktur?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
betagurke
User
Beiträge: 7
Registriert: Donnerstag 30. April 2020, 00:13

Hallo liebe Community,

vorerst: Ich bin neu hier! :D

um die Corona-Freizeit nicht nur sinnlos zu verdaddeln, dachte ich mir, dass ich das Projekt "Python lernen" mal in Angriff nehmen.

Kenntnisstand:
1) Ich weiß, dass man ".py" hinter den Dateinamen hängt
2) Kann mit "print" umgehen (sehr versiert)
3) Hat die Terminal-Schriftfarbe in grün geändert (für die Stimmung)

Aktuelles Projekt: Ein simpler ALG1-Rechner

Code:

Code: Alles auswählen

print("")
print("Herzlich Willkommen zum ALG1-Rechner (simple) v1.0")
print("")
print("")

# Eingabe des Brutto als Grundwert
print("Geben Sie Ihr durchschnittliches Bruttoeinkommen der letzten zwölf Monate ein: " )
brutto = input()
print("Ihr durchschnittliches mntl. Bruttoeinkommen (als Ganzzahl) der letzten 12 Monate beläuft sich auf: ",brutto,"€")
print("")

# Umwandlung Brutto in int
bruttoz = int(brutto)

#Berechnung 1) Bemessungsentgelt täglich (Brutto pro Monat x 12)
print("++++ Berechnung des täglichen Bemesseungsentgelds ++++ ")
bruttojahr = bruttoz * 12
print("Ihr Jahresbrutto der letzten 12 Monate: ",bruttojahr,"€")
bmess = bruttojahr / 365
print("Ihr tägliches Bemesseungsentgeld beläuft sich auf: ", bmess,"€")
print("")

#Berechnung 2) SV, LSt, Soli
print("++++ Berechnung der Abzüge für SV, Lohnsteuer und Soli ++++ ")
svpausch = bmess / 100 * 20
print("SV-Pauschale 20%:",svpausch,"€")
lohnst = bmess / 100 * 10
print("Lohnsteuer-Pauschale 10%:",lohnst,"€")
soli = lohnst / 100 * 5.5
print("Soli-Pauschale 5.5%",soli,"€")
abzuege = svpausch + lohnst + soli
print("Gesamtabzüge vom täglichen Bemmessungsentgelt:",abzuege,"€")
print("")


#Berechnung 3) Leistungsentgelt täglich
lgeld = bmess - abzuege
print("++++ Ihr tägliches Leistungsentgeld beläuft sich auf: ",lgeld,"€")
print()

#Berechnung 4) Leistungssatz täglich mit zwei verschiedenen User Eingaben (mit Kind / ohne Kind)
print("Bitte nennen Sie mir den Prozentwert zur Berechnung - info: 60% ohne Kind, 67% mit Kind")
proz = input()
prozint = int(proz)
lsatz = lgeld / 100 * prozint
print("Ihr täglicher Leistungssatz beläuft sich auf: ",lsatz,"€")
print()
alg1 = lsatz * 30
print("Ihr monatliches ALG1-Einkommen beläuft sich auf: "
      ,alg1,
      "€")
Anmerkung: Inzwischen weiß ich, dass ich die Zeilen eher mit "\n" statt mit Leerausgaben über print() trennen sollte - Update folgt.

Geplante Funktionen
Ich möchte mein kleines Berechnungsscript gerne "updaten" bzw. "erweitern. Konkret möchte ich folgende Funktionen einbauen
1) Eine Tabelle für die einzelnen Lohnsteuerklassen
2) Eine genaue Berechnung für die Lohnsteuer (inkl. Freibeträge, kein Pauschalwert)
3) Auswahl für den Prozentsatz bei "proz", statt einer Ganzzahl-Nutzereingabe sollen dort zwei Auswahlfelder (1 - mit Kind - 67%, 2 - ohne Kind - 60%) eingebunden werden, sodass der User nur 1 oder 2 zur Auswahl drücken muss.
4) Rundung der Zwischenergebnisse auf max. 3 Nachkommastellen in der Ausgabe

Fragen:
Erstmal Entwarnung: ich möchte von Euch nicht wissen, wie Schritt 1-4 im Code aussehen muss - da würde der Lerneffekt verlorengehen!

Meine Frage ist viel mehr, in welcher "Struktur" bzw. in welchem Ablauf man das in der Praxis gestalten würde - erfasst man die "dynamischen Werte" wie die LohnSt-Klasse oder den Prozentwert direkt am Anfang oder erst, wenn die entsprechende Berechnung durchgeführt wird?

Bei den ganzen Steuer- und ALG-Rechner im Internet gibt man VOR der Berechnung alle notwendigen Daten (Bundesland, Steuerklasse, etc.) ein und anschließend wird das Ergebnis ausgerechnet. In meinem Beispiel (zumindest bei dem Prozentwert "proz" wird erst bei der eigentlichen Frage eine Eingabe erwartet). Wie ist der Aufwand, wenn ich diese Daten in einem "temporären User-Input-File" speichern möchte, das anschließend bei der Berechnung genutzt wird? Oder würdet ihr mir - auf meinem Niveau - eher empfehlen, die Fragen nacheinander abzuarbeiten?

Zusatzfrage:
Habt ihr weitere Ideen für "Anfänger-Scripts"? - Würde mich über Vorschläge / Ideen sehr freuen, unabhängig davon, ob es meinem aktuellen Kenntnissstand entspricht. Ich lerne einfach besser, wenn ich einen praktischen Anwendungszweck hinter der Sache sehe - muss nicht unbedingt mit Berechnungen irgendwelcher Steuern zusammenhängen.
Ein kleines Spiel, ein Taschenrechner, Mini-Datenbank, Dateimanagement-Tool, etc. - irgendwas in die Richtung. Muss nichts ausführliches sein, Links oder Keysword reichen mir! :) Am Besten etwas, wo man sich anschließend denkt "Was, das geht damit? Ist ja cool!".


Danke erstmal für Eure Aufmerksamkeit und ggf. für Eure Hilfe!

Beste Grüße,
gurke
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@betagurke: Was als erstes auffällt sind die Namen: Keine kryptischen Abkürzungen und Namenszusätze verwenden. Und Grunddatentypen gehören nicht in Namen. Das wurde auch inkonsistent gelöst bei den beiden Eingaben: Einmal wurde der Name durch ein `z` ergänzt, das zweite mal durch ein `int`. Letztlich sollten beide Namen so nicht existieren — man muss nicht jedes Zwischenergebnis an einen Namen binden. Als Zeichenkette wird die Eingabe ja nicht wirklich gebraucht.

Kommentare sollten dem Leser einen Mehrwert über den Code liefern. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da ja bereits als Code, sondern warum er das so macht. Sofern das nicht offensichtlich ist.

`input()` kann man ein Argument übergeben.

Ein Leerzeichen nach Kommas erhöht die Lesbarkeit.

Man trennt für gewöhnlich die Benutzerinteraktion und die Programmlogik, damit man die Programmlogik unabhängig testen und wiederverwenden kann. Wenn Du Beispielsweise irgendwann mal, nachdem Du objektorientierte Programmierung gelernt hast, eine GUI für die ALG1-Berechnung schreiben möchtest, dann gäbe es kein `input()` und kein `print()` mehr, aber die Berechnungen bleiben ja die gleichen, müssten also dafür eigentlich nicht neu geschrieben werden.

Mehrere Argumente bei `print()` erscheint praktisch, aber man hat halt so Nachteile wie das Leerzeichen zwischen dem Betrag und dem €-Zeichen und das man die Nachkommastellen nicht im Griff hat. Beide Probleme hat man nicht wenn man *eine* Zeichenkette ausgibt, die man mit Zeichenkettenformatierung mit der `format()`-Methode oder f-Zeichenkettenliteralen erstellt. Das mit den Nachkommastellen zur Anzeige sollte man auch dort erledigen und nicht mit `round()` bei den Werten mit denen man weiterrechnen möchte. Es sei denn die Berechnungsvorschriften sagen explizit das mit gerundeten Werten weitergerechnet werden soll. Dann sollte man sich aber auch genau anschauen *wie* die gerundet werden müssen, denn `round()` macht nicht unbedingt das was viele naiverweise erwarten würden.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    print()
    print("Herzlich Willkommen zum ALG1-Rechner (simple) v1.0")
    print()
    print()

    brutto_monatseinkommen = int(
        input(
            "Geben Sie Ihr durchschnittliches, monatliches Bruttoeinkommen"
            " der letzten zwölf Monate ein:\n"
        )
    )
    print(
        "Ihr durchschnittliches, monatliches Bruttoeinkommen der letzten"
        " 12 Monate beläuft sich auf:",
        brutto_monatseinkommen,
        "€",
    )
    print()

    print("++++ Berechnung des täglichen Bemesseungsentgelds ++++ ")
    brutto_jahreseinkommen = brutto_monatseinkommen * 12
    print(
        "Ihr Jahresbrutto der letzten 12 Monate:", brutto_jahreseinkommen, "€"
    )
    taegliches_bemessungsentgeld = brutto_jahreseinkommen / 365
    print(
        "Ihr tägliches Bemesseungsentgeld beläuft sich auf:",
        taegliches_bemessungsentgeld,
        "€",
    )
    print()
    #
    # TODO Magische Zahlen als Konstanten herausziehen und auch in die
    # Zeichenketten einfügen.
    #
    print("++++ Berechnung der Abzüge für SV, Lohnsteuer und Soli ++++ ")
    sozialversicherungspauschale = taegliches_bemessungsentgeld * 0.2
    print("SV-Pauschale 20%:", sozialversicherungspauschale, "€")
    lohnsteuer_pauschale = taegliches_bemessungsentgeld * 0.1
    print("Lohnsteuer-Pauschale 10%:", lohnsteuer_pauschale, "€")
    soli_pauschale = lohnsteuer_pauschale * 0.055
    print("Soli-Pauschale 5.5%", soli_pauschale, "€")
    abzuege = (
        sozialversicherungspauschale + lohnsteuer_pauschale + soli_pauschale
    )
    print("Gesamtabzüge vom täglichen Bemmessungsentgelt:", abzuege, "€")
    print()

    leistungsentgeld = taegliches_bemessungsentgeld - abzuege
    print(
        "++++ Ihr tägliches Leistungsentgeld beläuft sich auf:",
        leistungsentgeld,
        "€",
    )
    print()

    prozentsatz = int(
        input(
            "Bitte nennen Sie mir den Prozentwert zur Berechnung"
            " - info: 60% ohne Kind, 67% mit Kind:\n"
        )
    )
    leistungssatz = leistungsentgeld / 100 * prozentsatz
    print("Ihr täglicher Leistungssatz beläuft sich auf:", leistungssatz, "€")
    print()
    alg1 = leistungssatz * 30
    print("Ihr monatliches ALG1-Einkommen beläuft sich auf:", alg1, "€")


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
betagurke
User
Beiträge: 7
Registriert: Donnerstag 30. April 2020, 00:13

Hey, das mit den Namen klingt einleuchtend, so bleibt es - später bei umfangreicheren Projekten - dennoch übersichtlich. Danke für den Tipp.

Per Input ein Argument übergeben macht Sinn und spart Platz, würde in der Praxis dann aussehen wie in deinem Beispiel bzw. so

Code: Alles auswählen

 
name = print(input("TextTextext")) 
statt

Code: Alles auswählen

name=print("TextTextText")
xyz = input() 
Bezüglich der magischen Zahlen habe ich per Google relativ viel gefunden, aber relativ wenig verstanden. Im Index meines Buches gibt es dazu keinen Eintrag, also entweder wird das dort nicht behandelt oder die Bezeichnung dort ist eine andere. Ich vermute aber, dass das zu einem späteren Zeitpunkt behandelt wird.

Nur zum Verständnis:

Ich kann einen Operator wie "+" auch mit der Methode "object.__add__(self, other)" "ersetzen". Aber wie genau würde das in der Praxis aussehen?

Danke für die ausführliche Antwort! :)
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Hättest du dein Beispiel ausprobiert, wüsstest Du dass es falsch ist.

Code: Alles auswählen

 
xyz = input("TextTextext")
Denn Rückgabewert von print an eine Variable zu binden, ist Unsinn, weil das immer None ist.
Zu magischen Zahlen und anderen Tipps, wie gut strukturierte Programme aussehen, steht in Büchern fast nie etwas, außer wenigen Ausnahmen, in denen genau das das Hauptthema ist. Die sind dann meist unabhängig von der Programmiersprache.

In der Praxis benutzt man keine magischen Methoden. Wenn man Operatoren braucht, nimmt man die aus dem operators-Modul.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@betagurke: ”Magische” Zahlen sind Zahlen die als literale Zahlen im Quelltext stehen und eine Bedeutung haben die man der Zahl selbst natürlich nicht ansieht. Bei dem gezeigten Code sind das beispielsweise die Prozentsätze der Pauschalen. So etwas definiert man üblicherweise als Konstanten. Dann steht da nicht nur ``* 0.2`` im Code sondern ``* SOZIALVERSICHERUNGS_PROZENTSATZ``. Dann weiss der Leser was die 0.2 *bedeutet*. Man kann die einfach an einer Stelle im Programm ändern wenn sich dieser Wert mal ändert. Denn der Wert steht ja im Grunde an zwei Stellen: In der Rechnung und in der `print()`-Ausgabe.

Bezüglich der magischen Methoden für Operatoren:

Code: Alles auswählen

In [164]: a, b = 42, 23                                                         

In [165]: a + b                                                                 
Out[165]: 65

In [166]: a.__add__(b)  # Macht man in der Praxis so nicht!
Out[166]: 65

In [167]: import operator                                                       

In [168]: operator.add(a, b)                                                    
Out[168]: 65
Wie Sirius3 schon sagte, ruft man die magischen Methoden nicht selbst auf. Ausnahme sind in der Regel das Aufrufen von magischen Methoden der Basisklasse wenn man die in einer abgeleiteten Klasse überschreibt und das ursprüngliche Verhalten Teil der neuen Implementierung sein soll. Am häufigsten betrifft das die `__init__()` und am zweit häufigsten wahrscheinlich `__str__()` und `__repr__()`.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten