4. Toepassingsopdracht – [IMPOTS]
![]() |
4.1. Het probleem
We willen een programma schrijven waarmee de belasting van een belastingplichtige kan worden berekend. We gaan uit van het vereenvoudigde geval van een belastingplichtige die alleen zijn salaris hoeft aan te geven:
- we berekenen het aantal aandelen van de werknemer nbParts=nbEnfants/2 +1 als hij ongehuwd is, nbEnfants/2+2 als hij getrouwd is, waarbij nbEnfants het aantal kinderen is;
- zijn belastbaar inkomen R wordt berekend als R = 0,72 * S, waarbij S zijn jaarsalaris is;
- vervolgens wordt zijn gezinscoëfficiënt Q = R/N berekend;
- zijn belasting I wordt berekend op basis van de volgende gegevens.
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
Elke regel heeft 3 velden. Om belasting I te berekenen, zoeken we de eerste regel waar QF <= veld1. Als bijvoorbeeld QF = 30000 is, vinden we de regel:
Belasting I is dan gelijk aan 0,15*R - 2072,5*nbParts. Als QF zodanig is dat de relatie QF<=veld1 nooit geldt, dan worden de coëfficiënten van de laatste regel gebruikt. In dit geval:
wat de belasting I = 0,65*R - 49062*nbParts oplevert.
4.2. Versie met lijsten
# -*- coding=utf-8 -*-
import math, sys
def cutNewLineChar(ligne):
# de regeleinde-markering wordt verwijderd, indien aanwezig
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):
# getrouwd: ja, nee
# kinderen: aantal kinderen
# salaris: jaarsalaris
# aantal aandelen
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# een half aandeel extra bij ten minste 3 kinderen
if enfants>=3:
nbParts+=0.5
# belastbaar inkomen
revenuImposable=0.72*salaire
# gezinsquotiënt
quotient=revenuImposable/nbParts
# wordt aan het einde van de tabel met drempels geplaatst om de daaropvolgende lus te beëindigen
limites[len(limites)-1]=quotient
# berekening van de belasting
i=0
while(quotient>limites[i]):
i=i+1
# omdat de gezinsquotiënt aan het einde van de limiettabel is geplaatst, wordt de voorgaande lus
# kan niet buiten de grenzen van de limiettabel vallen
# nu kan de belasting worden berekend
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ hoofdprogramma
# definitie van de constanten
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]
# gegevens inlezen
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# het resultatenbestand openen
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# de huidige regel van het gegevensbestand wordt verwerkt
ligne=data.readline()
while(ligne != ''):
# eventueel einde-van-regel-teken verwijderen
ligne=cutNewLineChar(ligne)
# de 3 velden 'gehuwd:kinderen:salaris' die de regel vormen, worden opgehaald
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# de belasting wordt berekend
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# het resultaat wordt opgeschreven
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# er wordt een nieuwe regel ingelezen
ligne=data.readline()
# de bestanden worden gesloten
data.close()
resultats.close()
Het gegevensbestand data.txt:
De resultats.txt-bestanden met de verkregen resultaten:
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. Versie met tekstbestanden
In het vorige voorbeeld werden de gegevens die nodig zijn voor de berekening van de belasting in drie lijsten gevonden. Voortaan worden ze in een tekstbestand opgezocht:
# -*- coding=utf-8 -*-
import math,sys
# --------------------------------------------------------------------------
def getTables(IMPOTS):
# IMPOTS: de naam van het bestand met de gegevens van de limiettabellen, coeffR, coeffN
# Bestaat het bestand IMPOTS?
try:
data=open(IMPOTS,"r")
except:
return ("Le fichier IMPOTS n'existe pas",0,0,0)
# aanmaken van de 3 lijsten – er wordt aangenomen dat de regels syntactisch correct zijn
# -- regel 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])
# -- regel 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])
# -- regel 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])
# einde
return ("",limites,coeffR,coeffN)
# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
# het einde-van-regel-teken wordt verwijderd, indien aanwezig
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):
# getrouwd: ja, nee
# kinderen: aantal kinderen
# salaris: jaarsalaris
# aantal aandelen
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# een half aandeel extra bij ten minste 3 kinderen
if enfants>=3:
nbParts+=0.5
# belastbaar inkomen
revenuImposable=0.72*salaire
# gezinsquotiënt
quotient=revenuImposable/nbParts
# wordt aan het einde van de tabel met drempels geplaatst om de daaropvolgende lus te beëindigen
limites[len(limites)-1]=quotient
# berekening van de belasting
i=0
while(quotient>limites[i]):
i=i+1
# omdat de gezinsquotiënt aan het einde van de limiettabel is geplaatst, wordt de voorgaande lus
# kan niet buiten de grenzen van de limiettabel vallen
# nu kan de belasting worden berekend
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ hoofdprogramma
# definitie van de constanten
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# de gegevens die nodig zijn voor de berekening van de belasting zijn in het bestand IMPOTS geplaatst
# met één regel per tabel in de vorm
# val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)
# Is er een fout opgetreden?
if(erreur):
print "{0}\n".format(erreur)
sys.exit()
# gegevens lezen
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# het resultatenbestand openen
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# de huidige regel van het gegevensbestand wordt verwerkt
ligne=data.readline()
while(ligne != ''):
# eventueel einde-van-regel-teken wordt verwijderd
ligne=cutNewLineChar(ligne)
# de 3 velden 'gehuwd:kinderen:salaris' die de regel vormen, worden opgehaald
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# de belasting wordt berekend
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# het resultaat wordt opgeschreven
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# er wordt een nieuwe regel ingelezen
ligne=data.readline()
# de bestanden worden gesloten
data.close()
resultats.close()
Dezelfde als hierboven.
De bovenstaande methode getImpots (regels 6-36) retourneert een tuple (erreur, limites, coeffR, coeffN), waarbij erreur een foutmelding is die eventueel leeg kan zijn. Het kan wenselijk zijn om deze foutgevallen met uitzonderingen af te handelen. In dat geval:
- in geval van een fout genereert de methode getImpots een uitzondering;
- anders retourneert ze de tuple (limites, coeffR, coeffN).
De code van de methode getImpots ziet er dan als volgt uit:
def getTables(IMPOTS):
# IMPOTS: de bestandsnaam die de gegevens van de limiettabellen bevat, coeffR, coeffN
# bestaat het bestand IMPOTS? zo niet, dan wordt in dit geval de uitzondering IOError gegenereerd
data=open(IMPOTS,"r")
# aanmaak van de 3 lijsten – er wordt aangenomen dat de regels syntactisch correct zijn
# -- regel 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])
# -- regel 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])
# -- regel 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])
# einde
return (limites,coeffR,coeffN)
- regel 4: er wordt niet gecontroleerd of het openen van het bestand mislukt. Als dit mislukt, wordt een uitzondering IOError gegenereerd. Deze wordt doorgegeven aan het aanroepende programma;
- regels 9-10: er wordt een uitzondering gegenereerd om aan te geven dat de verwachte eerste regel ontbreekt. Hiervoor wordt een vooraf gedefinieerde uitzondering RuntimeError gebruikt. Het is ook mogelijk om eigen uitzonderingsklassen te maken. Dit zullen we iets verderop doen;
- regels 16-17 en 23-24: we doen hetzelfde voor de regels 2 en 3.
De code van het hoofdprogramma ziet er dan als volgt uit:
# ------------------------------------------------ main
# definitie van de constanten
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# de gegevens die nodig zijn voor de berekening van de belasting zijn in het bestand IMPOTS geplaatst
# met één regel per tabel in de vorm
# val1:val2:val3,...
erreur=False
try:
(limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
erreur=True
except RuntimeError, message:
erreur=True
# Is er een fout opgetreden?
if(erreur):
print "L'erreur suivante s'est produite : {0}\n".format(message)
sys.exit()
# gegevens lezen
...
- regels 12-17: we roepen de methode getImpots aan en vangen de twee uitzonderingen op die deze kan genereren: IOError en RuntimeError. Bij deze afhandeling volstaan we met te vermelden dat er een fout is opgetreden;
- regels 20-22: we geven de foutmelding van de opgevangen uitzondering weer en beëindigen het programma.
