V. Exercice d'application - [IMPÔTS]▲
V-A. Le problème▲
On se propose d'écrire un programme permettant de calculer l'impôt d'un contribuable. On se place dans le cas simplifié d'un contribuable n'ayant que son seul salaire à déclarer :
- on calcule le nombre de parts du salarié nbParts=nbEnfants/2 +1 s'il n'est pas marié, nbEnfants/2+2 s'il est marié, où nbEnfants est son nombre d'enfants ;
- on calcule son revenu imposable R=0.72*S où S est son salaire annuel ;
- on calcule son coefficient familial Q=R/N ;
- on calcule son impôt I d'après les données suivantes
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
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
Chaque ligne a trois champs. Pour calculer l'impôt I, on recherche la première ligne où QF<=champ1. Par exemple, si QF=30000 on trouvera la ligne :
24740 0.15 2072.5
L'impôt I est alors égal à 0.15*R - 2072.5*nbParts. Si QF est tel que la relation QF<=champ1 n'est jamais vérifiée, alors ce sont les coefficients de la dernière ligne qui sont utilisés. Ici :
0 0.65 49062
ce qui donne l'impôt I=0.65*R - 49062*nbParts.
V-B. Version avec listes▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
# -*- coding=utf-8 -*-
import
math, sys
def
cutNewLineChar
(
ligne):
# on supprime la marque de fin de ligne si elle existe
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):
# marié : oui, non
# enfants : nombre d'enfants
# salaire : salaire annuel
# nombre de parts
marie=
marie.lower
(
)
if
(
marie==
"oui"
):
nbParts=
float(
enfants)/
2
+
2
else
:
nbParts=
float(
enfants)/
2
+
1
# une 1/2 part de plus si au moins 3 enfants
if
enfants>=
3
:
nbParts+=
0.5
# revenu imposable
revenuImposable=
0.72
*
salaire
# quotient familial
quotient=
revenuImposable/
nbParts
# est mis à la fin du tableau limites pour arrêter la boucle qui suit
limites[len(
limites)-
1
]=
quotient
# calcul de l'impôt
i=
0
while
(
quotient>
limites[i]):
i=
i+
1
# du fait qu'on a placé quotient à la fin du tableau limites, la boucle précédente
# ne peut déborder du tableau limites
# maintenant on peut calculer l'impôt
return
math.floor
(
revenuImposable*
coeffR[i]-
nbParts*
coeffN[i])
# ------------------------------------------------ main
# définition des constantes
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
]
# lecture des données
try
:
data=
open(
DATA,"r"
)
except
:
print
"Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit
(
)
# ouverture fichier des résultats
try
:
resultats=
open(
RESULTATS,"w"
)
except
:
print
"Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit
(
)
# on exploite la ligne courante du fichier des données
ligne=
data.readline
(
)
while
(
ligne !=
''
):
# on enlève l'éventuelle marque de fin de ligne
ligne=
cutNewLineChar
(
ligne)
# on récupère les 3 champs marié:enfants:salaire qui forment la ligne
(
marie,enfants,salaire)=
ligne.split
(
","
)
enfants=
int(
enfants)
salaire=
int(
salaire)
# on calcule l'impôt
impot=
calculImpots
(
marie,enfants,salaire,limites,coeffR,coeffN)
# on inscrit le résultat
resultats.write
(
"{0}:{1}:{2}:{3}
\n
"
.format
(
marie,enfants,salaire,impot))
# on lit une nouvelle ligne
ligne=
data.readline
(
)
# on ferme les fichiers
data.close
(
)
resultats.close
(
)
Résultats
2.
3.
4.
5.
6.
oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000
2.
3.
4.
5.
6.
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
V-C. Version avec fichiers texte▲
Dans l'exemple précédent, les données nécessaires au calcul de l'impôt avaient été trouvées dans trois listes. Elles seront désormais cherchées dans un fichier texte :
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
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
# -*- coding=utf-8 -*-
import
math,sys
# --------------------------------------------------------------------------
def
getTables
(
IMPOTS):
# IMPOTS : le nom du fichier contenant les données des tables limites, coeffR, coeffN
# le fichier IMPOTS existe-t-il ?
try
:
data=
open(
IMPOTS,"r"
)
except
:
return
(
"Le fichier IMPOTS n'existe pas"
,0
,0
,0
)
# création des 3 listes - on suppose que les lignes sont syntaxiquement correctes
# -- ligne 1
ligne=
data.readline
(
)
if
ligne==
''
:
return
(
"La 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])
# -- ligne 2
ligne=
data.readline
(
)
if
ligne==
''
:
return
(
"La 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])
# -- ligne 3
ligne=
data.readline
(
)
if
ligne==
''
:
return
(
"La 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])
# fin
return
(
""
,limites,coeffR,coeffN)
# --------------------------------------------------------------------------
def
cutNewLineChar
(
ligne):
# on supprime la marque de fin de ligne si elle existe
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):
# marié : oui, non
# enfants : nombre d'enfants
# salaire : salaire annuel
# nombre de parts
marie=
marie.lower
(
)
if
(
marie==
"oui"
):
nbParts=
float(
enfants)/
2
+
2
else
:
nbParts=
float(
enfants)/
2
+
1
# une 1/2 part de plus si au moins 3 enfants
if
enfants>=
3
:
nbParts+=
0.5
# revenu imposable
revenuImposable=
0.72
*
salaire
# quotient familial
quotient=
revenuImposable/
nbParts
# est mis à la fin du tableau limites pour arrêter la boucle qui suit
limites[len(
limites)-
1
]=
quotient
# calcul de l'impôt
i=
0
while
(
quotient>
limites[i]):
i=
i+
1
# du fait qu'on a placé quotient à la fin du tableau limites, la boucle précédente
# ne peut déborder du tableau limites
# maintenant on peut calculer l'impôt
return
math.floor
(
revenuImposable*
coeffR[i]-
nbParts*
coeffN[i])
# ------------------------------------------------ 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,limites,coeffR,coeffN)=
getTables
(
IMPOTS)
# y a-t-il eu une erreur ?
if
(
erreur):
print
"{0}
\n
"
.format
(
erreur)
sys.exit
(
)
# lecture des données
try
:
data=
open(
DATA,"r"
)
except
:
print
"Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit
(
)
# ouverture fichier des résultats
try
:
resultats=
open(
RESULTATS,"w"
)
except
:
print
"Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit
(
)
# on exploite la ligne courante du fichier des données
ligne=
data.readline
(
)
while
(
ligne !=
''
):
# on enlève l'éventuelle marque de fin de ligne
ligne=
cutNewLineChar
(
ligne)
# on récupère les 3 champs marié:enfants:salaire qui forment la ligne
(
marie,enfants,salaire)=
ligne.split
(
","
)
enfants=
int(
enfants)
salaire=
int(
salaire)
# on calcule l'impôt
impot=
calculImpots
(
marie,enfants,salaire,limites,coeffR,coeffN)
# on inscrit le résultat
resultats.write
(
"{0}:{1}:{2}:{3}
\n
"
.format
(
marie,enfants,salaire,impot))
# on lit une nouvelle ligne
ligne=
data.readline
(
)
# on ferme les fichiers
data.close
(
)
resultats.close
(
)
Résultats
Les mêmes que précédemment.
Programme (impots_02b)
La méthode getTables ci-dessus (lignes 6-36) rend un tuple (erreur, limites, coeffR, coeffN) où erreur est un message d'erreur éventuellement vide. On peut vouloir gérer ces cas d'erreurs avec des exceptions. Dans ce cas :
- en cas d'erreur, la méthode getTables lance une exception ;
- sinon elle rend le tuple (limites, coeffR, coeffN).
Le code de la méthode getTables devient alors le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
def
getTables
(
IMPOTS):
# IMPOTS : le nom du fichier contenant les données des tables limites, coeffR, coeffN
# le fichier IMPOTS existe-t-il ? Si non alors l'exception IOError est lancée dans ce cas
data=
open(
IMPOTS,"r"
)
# création des 3 listes - on suppose que les lignes sont syntaxiquement correctes
# -- ligne 1
ligne=
data.readline
(
)
if
ligne==
''
:
raise
RuntimeError
(
"La ligne du fichier {0} est absente"
.format
(
IMPOTS))
limites=
cutNewLineChar
(
ligne).split
(
":"
)
for
i in
range(
len(
limites)):
limites[i]=
int(
limites[i])
# -- ligne 2
ligne=
data.readline
(
)
if
ligne==
''
:
raise
RuntimeError
(
"La ligne du fichier {0} est absente"
.format
(
IMPOTS))
coeffR=
cutNewLineChar
(
ligne).split
(
":"
)
for
i in
range(
len(
coeffR)):
coeffR[i]=
float(
coeffR[i])
# -- ligne 3
ligne=
data.readline
(
)
if
ligne==
''
:
raise
RuntimeError
(
"La ligne du fichier {0} est absente"
.format
(
IMPOTS))
coeffN=
cutNewLineChar
(
ligne).split
(
":"
)
for
i in
range(
len(
coeffN)):
coeffN[i]=
float(
coeffN[i])
# fin
return
(
limites,coeffR,coeffN)
- ligne 4 : on ne teste pas si l'ouverture du fichier échoue. Si elle échoue, une exception IOError est lancée. On laisse celle-ci remonter au programme appelant ;
- lignes 9-10 : on lance une exception pour indiquer que la première ligne attendue est absente. On utilise une exception prédéfinie RuntimeError. On peut également créer ses propres classes d'exception. Nous le ferons un peu plus loin ;
- lignes 16-17 et 23-24 : on refait la même chose pour les lignes 2 et 3.
Le code du programme principal devient alors le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
# ------------------------------------------------ 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
...
- lignes 12-17 : on appelle la méthode getTables et on gère les deux exceptions qu'elle peut lancer : IOError et RuntimeError. Dans cette gestion, on se contente de noter qu'il y a eu erreur ;
- lignes 20-22 : on affiche le message d'erreur de l'exception interceptée et on arrête le programme.