Skip to content

4. Anwendungsaufgabe – [Steuerberechnung]

4.1. Die Aufgabe

Wir wollen ein Programm schreiben, das die Steuer eines Steuerpflichtigen berechnet. Wir betrachten den vereinfachten Fall eines Steuerpflichtigen, der nur sein Gehalt anzugeben hat:

  • Wir berechnen die Anzahl der Steuerklassen für den Arbeitnehmer nbParts = nbChildren / 2 + 1, wenn er unverheiratet ist, und nbChildren / 2 + 2, wenn er verheiratet ist, wobei nbChildren die Anzahl der Kinder ist;
  • wir berechnen sein zu versteuerndes Einkommen R = 0,72 * S, wobei S sein Jahresgehalt ist;
  • wir berechnen seinen Familienkoeffizienten Q = R/N;
  • wir berechnen seine Steuer I auf der Grundlage der folgenden Daten.
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, suchen Sie die erste Zeile, in der QF <= Feld1 ist. Wenn QF beispielsweise 30.000 beträgt, lautet die gefundene Zeile:

24740 0.15 2072.5

Steuer I entspricht dann 0,15*R – 2072,5*nbParts. Wenn QF so ist, dass die Bedingung QF <= Feld1 nie erfüllt ist, werden die Koeffizienten aus der letzten Zeile verwendet. Hier:

0 0.65 49062

was zu Steuer I = 0,65*R - 49062*nbParts führt.

4.2. Version mit Listen


Programm (impots_01)

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

import math, sys

def cutNewLineChar(ligne):
    #  delete the end-of-line mark if it exists
    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):
    #  married: yes, no
    #  children: number of children
    #  salary: annual salary

    #  number of shares
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    #  an additional 1/2 share if at least 3 children
    if enfants>=3:
        nbParts+=0.5
    #    taxable income
    revenuImposable=0.72*salaire
    #    family quotient
    quotient=revenuImposable/nbParts
    #  is set at the end of the limit table to stop the following loop
    limites[len(limites)-1]=quotient
    #  tAX CALCULATION
    i=0
    while(quotient>limites[i]):
        i=i+1
    #  because we've placed quotient at the end of the limit array, the previous loop
    #  cannot go beyond the limit table
    #  now we can calculate the tax
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


#    ------------------------------------------------ main
#    definition of constants
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]

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

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

#  use the current line of the data file
ligne=data.readline()
while(ligne != ''):
    #  remove any end-of-line marker
    ligne=cutNewLineChar(ligne)
    #  we retrieve the 3 fields married:children:salary which form the line
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    #  tax calculation
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    #  enter the result
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    #  a new line is read
    ligne=data.readline()
#    close files
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 „results.txt“ mit den 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 befanden sich die zur Berechnung der Steuer erforderlichen Daten in drei Listen. Von nun an werden sie aus einer Textdatei abgerufen:

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 (taxes_02)

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

import math,sys

# --------------------------------------------------------------------------
def getTables(IMPOTS):
    #  IMPOTS: the name of the file containing data from the limit tables, coeffR, coeffN
    #  does the IMPOTS file exist?
    try:
        data=open(IMPOTS,"r")
    except:
        return ("Le fichier IMPOTS n'existe pas",0,0,0)
    #  create the 3 lists - assume the lines are syntactically correct
    #  -- line 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])
    #  -- line 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])
    #  -- line 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])
    #    end
    return ("",limites,coeffR,coeffN)

# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
    #  delete the end-of-line mark if it exists
    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):
    #  married: yes, no
    #  children: number of children
    #  salary: annual salary

    #  number of shares
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    #  an additional 1/2 share if at least 3 children
    if enfants>=3:
        nbParts+=0.5
    #    taxable income
    revenuImposable=0.72*salaire
    #    family quotient
    quotient=revenuImposable/nbParts
    #  is set at the end of the limit array to stop the loop that follows
    limites[len(limites)-1]=quotient
    #  tAX CALCULATION
    i=0
    while(quotient>limites[i]):
        i=i+1
    #  because we've placed quotient at the end of the limit array, the previous loop
    #  cannot exceed the limits of the board
    #  now we can calculate the tax
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


#    ------------------------------------------------ main
#    definition of constants
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

#  the data required to calculate the tax has been placed in the IMPOTS file
#  one line per table in the form
#    val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)

#    was there a mistake?
if(erreur):
    print "{0}\n".format(erreur)
    sys.exit()

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

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

#  use the current line of the data file
ligne=data.readline()
while(ligne != ''):
    #  remove any end-of-line marker
    ligne=cutNewLineChar(ligne)
    #  we retrieve the 3 fields married:children:salary which form the line
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    #  tax calculation
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    #  enter the result
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    #  a new line is read
    ligne=data.readline()
#    close files
data.close()
resultats.close()

Ergebnisse

Wie zuvor.


Programm (taxes_02b)

Die obige Methode getImpots (Zeilen 6–36) gibt ein Tupel (error, limits, coeffR, coeffN*) zurück, wobei error* eine Fehlermeldung ist, die leer sein kann. Möglicherweise möchten Sie diese Fehlerfälle mithilfe von Ausnahmen behandeln. In diesem Fall:

  • Wenn ein Fehler auftritt, löst die Methode „getImpots“ eine Ausnahme aus;
  • ansonsten gibt sie das Tupel (limits, coeffR, coeffN) zurück.

Der Code für die Methode *getImpots* sieht dann wie folgt aus:

def getTables(IMPOTS):
    #  IMPOTS: the name of the file containing data from the limit tables, coeffR, coeffN
    #  does file IMPOTS exist? if not, exception IOError is thrown in this case
    data=open(IMPOTS,"r")

    #  create the 3 lists - assume the lines are syntactically correct
    #  -- line 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])
    #  -- line 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])
    #  -- line 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])
    #    end
    return (limites,coeffR,coeffN)
  • Zeile 4: Wir prüfen nicht, ob das Öffnen der Datei fehlschlägt. Falls dies der Fall ist, wird eine IOError-Ausnahme ausgelöst. Wir lassen diese an das aufrufende Programm weitergeben;
  • Zeilen 9–10: Wir lösen eine Ausnahme aus, um anzuzeigen, dass die erwartete erste Zeile fehlt. Wir verwenden eine vordefinierte RuntimeError-Ausnahme. Wir können auch eigene Ausnahmeklassen erstellen. Das werden wir etwas später tun;
  • Zeilen 16–17 und 23–24: Wir verfahren genauso für die Zeilen 2 und 3.

Der Hauptprogrammcode sieht dann wie folgt aus:


# ------------------------------------------------ main
# définition des constantes
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
 
# les données nécessaires au calcul de l'impôt ont été placées dans le fichier IMPOTS
# à raison d'une ligne par tableau sous la forme
# val1:val2:val3,...
 
erreur=False
try:
    (limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
    erreur=True
except RuntimeError, message:
    erreur=True
 
# y-a-t-il eu une erreur ?
if(erreur):
    print "L'erreur suivante s'est produite : {0}\n".format(message)
    sys.exit()
 
# lecture des données
...
  • Zeilen 12–17: Wir rufen die Methode getImpots auf und behandeln die beiden Ausnahmen, die dabei auftreten können: IOError und RuntimeError. Bei dieser Behandlung vermerken wir lediglich, dass ein Fehler aufgetreten ist;
  • Zeilen 20–22: Wir zeigen die Fehlermeldung der abgefangenen Ausnahme an und beenden das Programm.