Skip to content

4. Anwendungsübung – [IMPOTS]

4.1. Die Aufgabe

Es soll ein Programm geschrieben werden, mit dem die Steuer eines Steuerpflichtigen berechnet werden kann. Wir betrachten den vereinfachten Fall eines Steuerpflichtigen, der nur sein Gehalt anzugeben hat:

  • Man berechnet die Anzahl der Anteile des Arbeitnehmers nbParts=nbEnfants/2 + 1, wenn er unverheiratet ist, nbEnfants/2+2, wenn er verheiratet ist, wobei nbEnfants die Anzahl seiner Kinder ist;
  • man berechnet sein zu versteuerndes Einkommen R = 0,72 * S, wobei S sein Jahresgehalt ist;
  • man berechnet seinen Familienkoeffizienten Q = R/N;
  • seine Steuer I wird anhand der folgenden Daten berechnet.
12620.0 0 0
13190 0.05 631
15640 0.1 1290.5
24740 0.15 2072.5
31810 0.2 3309.5
39970 0.25 4900
48360 0.3 6898.5
55790 0.35 9316.5
92970 0.4 12106
127860 0.45 16754.5
151250 0.50 23147.5
172040 0.55 30710
195000 0.60 39312
0 0.65 49062

Jede Zeile enthält 3 Felder. Um die Steuer I zu berechnen, wird die erste Zeile gesucht, in der QF <= Feld 1 gilt. Wenn beispielsweise QF = 30000 ist, wird folgende Zeile gefunden:

24740 0.15 2072.5

Die Steuer I beträgt dann 0,15*R – 2072,5*nbParts. Wenn QF so gewählt ist, dass die Beziehung QF <= Feld1 niemals erfüllt ist, werden die Koeffizienten der letzten Zeile verwendet. In diesem Fall:

0 0.65 49062

was die Steuer I = 0,65 * R – 49062 * nbParts ergibt.

4.2. Version mit Listen


Programm (impots_01)


# -*- coding=utf-8 -*-

import math, sys

def cutNewLineChar(ligne):
    # Die Zeilenende-Markierung wird entfernt, falls vorhanden
    l=len(ligne);
    while(ligne[l-1]=="\n" or ligne[l-1]=="\r"):
        l-=1
    return(ligne[0:l]);

  # --------------------------------------------------------------------------
def calculImpots(marie,enfants,salaire,limites,coeffR,coeffN):
    # verheiratet: ja, nein
    # Kinder: Anzahl der Kinder
    # Gehalt: Jahresgehalt

    # Anzahl der Anteile
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    # ein halber Anteil zusätzlich, wenn mindestens 3 Kinder vorhanden sind
    if enfants>=3:
        nbParts+=0.5
    # steuerpflichtiges Einkommen
    revenuImposable=0.72*salaire
    # Familienquotient
    quotient=revenuImposable/nbParts
    # wird am Ende der Tabelle „Grenzwerte“ eingefügt, um die folgende Schleife zu beenden
    limites[len(limites)-1]=quotient
    # Steuerberechnung
    i=0
    while(quotient>limites[i]):
        i=i+1
    # Da der Familienquotient am Ende des Grenzwert-Arrays platziert wurde, wird die vorherige Schleife
    # kann nicht über die Grenzen des Grenzwertetabells hinausgehen
    # Nun kann die Steuer berechnet werden
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


# ------------------------------------------------ Hauptprogramm
# Definition der Konstanten
DATA="data.txt"
RESULTATS="resultats.txt"
limites=[12620,13190,15640,24740,31810,39970,48360,55790,92970,127860,151250,172040,195000,0]
coeffR=[0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65]
coeffN=[0,631,1290.5,2072.5,3309.5,4900,6898.5,9316.5,12106,16754.5,23147.5,30710,39312,49062]

# Daten einlesen
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

# Ergebnisdatei öffnen
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

# Auswertung der aktuellen Zeile der Datendatei
ligne=data.readline()
while(ligne != ''):
    # Eventuelles Zeilenendezeichen wird entfernt
    ligne=cutNewLineChar(ligne)
    # die drei Felder „verheiratet:Kinder:Gehalt“, aus denen die Zeile besteht, werden abgerufen
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    # Die Steuer wird berechnet
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    # Das Ergebnis wird eingetragen
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    # eine neue Zeile wird gelesen
    ligne=data.readline()
# Die Dateien werden geschlossen
data.close()
resultats.close()

Ergebnisse

Die Datendatei data.txt:

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Die Datei resultats.txt mit den erzielten Ergebnissen:

oui:2:200000:22504.0
non:2:200000:33388.0
oui:3:200000:16400.0
non:3:200000:22504.0
oui:5:50000:0.0
non:0:3000000:1354938.0

4.3. Version mit Textdateien

Im vorherigen Beispiel wurden die für die Steuerberechnung erforderlichen Daten in drei Listen gefunden. Künftig werden sie in einer Textdatei gesucht:

1
2
3
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062

Programm (impots_02)


# -*- coding=utf-8 -*-

import math,sys

# --------------------------------------------------------------------------
def getTables(IMPOTS):
    # IMPOTS: Name der Datei, die die Daten der Grenztabellen enthält, coeffR, coeffN
    # Gibt es die Datei IMPOTS?
    try:
        data=open(IMPOTS,"r")
    except:
        return ("Le fichier IMPOTS n'existe pas",0,0,0)
    # Erstellung der 3 Listen – es wird davon ausgegangen, dass die Zeilen syntaktisch korrekt sind
    # -- Zeile 1
    ligne=data.readline()
    if ligne== '':
        return ("La premiere ligne du fichier {0} est absente".format(IMPOTS),0,0,0)
    limites=cutNewLineChar(ligne).split(":")
    for i in range(len(limites)):
        limites[i]=int(limites[i])
    # -- Zeile 2
    ligne=data.readline()
    if ligne== '':
        return ("La deuxieme ligne du fichier {0} est absente".format(IMPOTS),0,0,0)
    coeffR=cutNewLineChar(ligne).split(":")
    for i in range(len(coeffR)):
        coeffR[i]=float(coeffR[i])
    # – Zeile 3
    ligne=data.readline()
    if ligne== '':
        return ("La troisieme ligne du fichier {0} est absente".format(IMPOTS),0,0,0)
    coeffN=cutNewLineChar(ligne).split(":")
    for i in range(len(coeffN)):
        coeffN[i]=float(coeffN[i])
    # Ende
    return ("",limites,coeffR,coeffN)

# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
    # Die Zeilenende-Markierung wird entfernt, falls vorhanden
    l=len(ligne);
    while(ligne[l-1]=="\n" or ligne[l-1]=="\r"):
        l-=1
    return(ligne[0:l]);

  # --------------------------------------------------------------------------
def calculImpots(marie,enfants,salaire,limites,coeffR,coeffN):
    # verheiratet: ja, nein
    # Kinder: Anzahl der Kinder
    # Gehalt: Jahresgehalt

    # Anzahl der Anteile
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    # ein halber Anteil zusätzlich, wenn mindestens 3 Kinder vorhanden sind
    if enfants>=3:
        nbParts+=0.5
    # steuerpflichtiges Einkommen
    revenuImposable=0.72*salaire
    # Familienquotient
    quotient=revenuImposable/nbParts
    # wird am Ende der Tabelle „Grenzwerte“ eingefügt, um die folgende Schleife zu beenden
    limites[len(limites)-1]=quotient
    # Steuerberechnung
    i=0
    while(quotient>limites[i]):
        i=i+1
    # Da der Familienquotient am Ende des Grenzwert-Arrays platziert wurde, wird die vorherige Schleife
    # kann nicht über die Grenzen des Grenzwertetabells hinausgehen
    # Nun kann die Steuer berechnet werden
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


# ------------------------------------------------ Hauptprogramm
# Definition der Konstanten
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

# Die für die Steuerberechnung erforderlichen Daten wurden in die Datei IMPOTS geschrieben
# mit jeweils einer Zeile pro Tabelle in der Form
# val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)

# Ist ein Fehler aufgetreten?
if(erreur):
    print "{0}\n".format(erreur)
    sys.exit()

# Daten werden gelesen
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

# Ergebnisdatei öffnen
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

# Die aktuelle Zeile der Datendatei wird verarbeitet
ligne=data.readline()
while(ligne != ''):
    # Das eventuelle Zeilenendezeichen wird entfernt
    ligne=cutNewLineChar(ligne)
    # die drei Felder „verheiratet:Kinder:Gehalt“, aus denen die Zeile besteht, werden abgerufen
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    # Die Steuer wird berechnet
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    # Das Ergebnis wird eingetragen
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    # eine neue Zeile wird gelesen
    ligne=data.readline()
# Die Dateien werden geschlossen
data.close()
resultats.close()

Ergebnisse

Die gleichen wie zuvor.


Programm (impots_02b)

Die oben genannte Methode getImpots (Zeilen 6–36) gibt ein Tupel zurück (erreur, limites, coeffR, coeffN), wobei erreur eine möglicherweise leere Fehlermeldung ist. Man möchte diese Fehlerfälle möglicherweise mit Ausnahmen behandeln. In diesem Fall:

  • Im Fehlerfall löst die Methode getImpots eine Ausnahme aus;
  • Andernfalls gibt sie das Tupel (limites, coeffR, coeffN) zurück.

Der Code der Methode getImpots sieht dann wie folgt aus:


def getTables(IMPOTS):
    # IMPOTS: Name der Datei, die die Daten der Grenztabellen enthält, coeffR, coeffN
    # Existiert die Datei IMPOTS? Falls nicht, wird in diesem Fall die Ausnahme IOError ausgelöst
    data=open(IMPOTS,"r")
  
    # Erstellung der 3 Listen – es wird davon ausgegangen, dass die Zeilen syntaktisch korrekt sind
    # -- Zeile 1
    ligne=data.readline()
    if ligne== '':
        raise RuntimeError ("La premiere ligne du fichier {0} est absente".format(IMPOTS))
    limites=cutNewLineChar(ligne).split(":")
    for i in range(len(limites)):
        limites[i]=int(limites[i])
    # – Zeile 2
    ligne=data.readline()
    if ligne== '':
        raise RuntimeError ("La deuxieme ligne du fichier {0} est absente".format(IMPOTS))
    coeffR=cutNewLineChar(ligne).split(":")
    for i in range(len(coeffR)):
        coeffR[i]=float(coeffR[i])
    # – Zeile 3
    ligne=data.readline()
    if ligne== '':
        raise RuntimeError ("La troisieme ligne du fichier {0} est absente".format(IMPOTS))
    coeffN=cutNewLineChar(ligne).split(":")
    for i in range(len(coeffN)):
        coeffN[i]=float(coeffN[i])
    # Ende
    return (limites,coeffR,coeffN)
  • Zeile 4: Es wird nicht geprüft, ob das Öffnen der Datei fehlschlägt. Falls dies der Fall ist, wird eine Ausnahme vom Typ IOError ausgelöst. Diese wird an das aufrufende Programm weitergeleitet;
  • Zeilen 9–10: Es wird eine Ausnahme ausgelöst, um anzuzeigen, dass die erwartete erste Zeile fehlt. Dabei wird eine vordefinierte Ausnahme RuntimeError verwendet. Man kann auch eigene Ausnahmeklassen erstellen. Dies werden wir etwas später tun;
  • Zeilen 16–17 und 23–24: Das Gleiche wird für die Zeilen 2 und 3 wiederholt.

Der Code des Hauptprogramms sieht dann wie folgt aus:


# ------------------------------------------------ main
# Definition der Konstanten
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

# Die für die Steuerberechnung erforderlichen Daten wurden in die Datei IMPOTS geschrieben
# mit jeweils einer Zeile pro Tabelle in der Form
# val1:val2:val3,...

erreur=False
try:
    (limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
    erreur=True
except RuntimeError, message:
    erreur=True

# Ist ein Fehler aufgetreten?
if(erreur):
    print "L'erreur suivante s'est produite : {0}\n".format(message)
    sys.exit()

# Daten werden gelesen
...
  • Zeilen 12–17: Wir rufen die Methode getImpots auf und behandeln die beiden Ausnahmen, die sie auslösen kann: IOError und RuntimeError. Bei dieser Behandlung beschränken wir uns darauf, zu vermerken, dass ein Fehler aufgetreten ist;
  • Zeilen 20–22: Die Fehlermeldung der abgefangenen Ausnahme wird angezeigt und das Programm wird beendet.