4. Esercizio pratico – [IMPOTS]
![]() |
4.1. Il problema
Si propone di scrivere un programma che consenta di calcolare l'imposta di un contribuente. Si considera il caso semplificato di un contribuente che abbia da dichiarare solo il proprio stipendio:
- si calcola il numero di quote del dipendente nbParts=nbEnfants/2 +1 se non è sposato, nbEnfants/2+2 se è sposato, dove nbEnfants è il numero dei suoi figli;
- si calcola il suo reddito imponibile R=0,72*S, dove S è il suo stipendio annuale;
- si calcola il suo coefficiente familiare Q = R/N;
- si calcola la sua imposta I in base ai seguenti dati.
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
Ogni riga contiene 3 campi. Per calcolare l'imposta I, si cerca la prima riga in cui QF ≤ campo1. Ad esempio, se QF = 30000, si troverà la riga:
L'imposta I è quindi pari a 0,15*R - 2072,5*nbParts. Se QF è tale che la relazione QF<=campo1 non è mai soddisfatta, allora vengono utilizzati i coefficienti dell’ultima riga. In questo caso:
il che dà l’imposta I=0,65*R - 49062*nbParts.
4.2. Versione con elenchi
# -*- coding=utf-8 -*-
import math, sys
def cutNewLineChar(ligne):
# si rimuove il carattere di fine riga, se presente
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):
# stato civile: sì, no
# figli: numero di figli
# stipendio: stipendio annuo
# numero di quote
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# una quota e mezza in più se ci sono almeno 3 figli
if enfants>=3:
nbParts+=0.5
# reddito imponibile
revenuImposable=0.72*salaire
# quoziente familiare
quotient=revenuImposable/nbParts
# viene inserito alla fine della tabella dei limiti per interrompere il ciclo successivo
limites[len(limites)-1]=quotient
# calcolo dell'imposta
i=0
while(quotient>limites[i]):
i=i+1
# poiché il quoziente è stato inserito alla fine della tabella dei limiti, il ciclo precedente
# non può andare oltre i limiti della tabella
# ora è possibile calcolare l’imposta
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ main
# definizione delle costanti
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]
# lettura dei dati
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# apertura del file dei risultati
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# si elabora la riga corrente del file dei dati
ligne=data.readline()
while(ligne != ''):
# si rimuove l'eventuale carattere di fine riga
ligne=cutNewLineChar(ligne)
# si recuperano i 3 campi coniugato:figli:stipendio che compongono la riga
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# si calcola l'imposta
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# si inserisce il risultato
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# si legge una nuova riga
ligne=data.readline()
# si chiudono i file
data.close()
resultats.close()
Il file dei dati data.txt:
I file resultats.txt dei risultati ottenuti:
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. Versione con file di testo
Nell'esempio precedente, i dati necessari per il calcolo dell'imposta erano stati ricavati da tre elenchi. D'ora in poi saranno ricavati da un file di testo:
# -*- coding=utf-8 -*-
import math,sys
# --------------------------------------------------------------------------
def getTables(IMPOTS):
# IMPOTS: il nome del file contenente i dati delle tabelle dei limiti, coeffR, coeffN
# Il file IMPOTS esiste?
try:
data=open(IMPOTS,"r")
except:
return ("Le fichier IMPOTS n'existe pas",0,0,0)
# creazione delle 3 liste - si presume che le righe siano sintatticamente corrette
# -- riga 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])
# -- riga 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])
# -- riga 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])
# fine
return ("",limites,coeffR,coeffN)
# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
# si elimina il carattere di fine riga se presente
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):
# stato civile: sì, no
# figli: numero di figli
# stipendio: stipendio annuo
# numero di quote
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# una quota e mezza in più se ci sono almeno 3 figli
if enfants>=3:
nbParts+=0.5
# reddito imponibile
revenuImposable=0.72*salaire
# quoziente familiare
quotient=revenuImposable/nbParts
# viene inserito alla fine della tabella dei limiti per interrompere il ciclo successivo
limites[len(limites)-1]=quotient
# calcolo dell'imposta
i=0
while(quotient>limites[i]):
i=i+1
# poiché il quoziente è stato inserito alla fine della tabella dei limiti, il ciclo precedente
# non può andare oltre i limiti della tabella
# ora è possibile calcolare l’imposta
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ main
# definizione delle costanti
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# i dati necessari per il calcolo dell'imposta sono stati inseriti nel file IMPOTS
# con una riga per ogni tabella nella forma
# val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)
# Si è verificato un errore?
if(erreur):
print "{0}\n".format(erreur)
sys.exit()
# lettura dei dati
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# apertura del file dei risultati
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# si elabora la riga corrente del file dei dati
ligne=data.readline()
while(ligne != ''):
# si rimuove l'eventuale carattere di fine riga
ligne=cutNewLineChar(ligne)
# si recuperano i 3 campi coniugato:figli:stipendio che compongono la riga
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# si calcola l'imposta
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# si inserisce il risultato
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# si legge una nuova riga
ligne=data.readline()
# si chiudono i file
data.close()
resultats.close()
Gli stessi di prima.
Il metodo getImpots sopra riportato (righe 6-36) restituisce una tupla (erreur, limites, coeffR, coeffN) in cui erreur è un messaggio di errore, eventualmente vuoto. Si potrebbe voler gestire questi casi di errore tramite eccezioni. In tal caso:
- in caso di errore, il metodo getImpots genera un'eccezione;
- altrimenti restituisce la tupla (limites, coeffR, coeffN).
Il codice del metodo getImpots diventa quindi il seguente:
def getTables(IMPOTS):
# IMPOTS: il nome del file contenente i dati delle tabelle limite, coeffR, coeffN
# il file IMPOTS esiste? In caso contrario, viene generata l'eccezione IOError
data=open(IMPOTS,"r")
# creazione dei 3 elenchi - si presume che le righe siano sintatticamente corrette
# -- riga 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])
# -- riga 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])
# -- riga 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])
# fine
return (limites,coeffR,coeffN)
- riga 4: non si verifica se l’apertura del file fallisce. Se fallisce, viene generata un’eccezione IOError. Si lascia che questa venga propagata al programma chiamante;
- righe 9-10: si genera un'eccezione per segnalare che la prima riga prevista è assente. Si utilizza un'eccezione predefinita RuntimeError. È anche possibile creare classi di eccezione personalizzate. Lo faremo più avanti;
- righe 16-17 e 23-24: si ripete la stessa operazione per le righe 2 e 3.
Il codice del programma principale diventa quindi il seguente:
# ------------------------------------------------ main
# definizione delle costanti
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# i dati necessari per il calcolo dell'imposta sono stati inseriti nel file IMPOTS
# con una riga per ogni tabella nella forma
# val1:val2:val3,...
erreur=False
try:
(limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
erreur=True
except RuntimeError, message:
erreur=True
# Si è verificato un errore?
if(erreur):
print "L'erreur suivante s'est produite : {0}\n".format(message)
sys.exit()
# lettura dei dati
...
- righe 12-17: si chiama il metodo getImpots e si gestiscono le due eccezioni che esso può generare: IOError e RuntimeError. In questa gestione, ci si limita a segnalare che si è verificato un errore;
- righe 20-22: si visualizza il messaggio di errore dell’eccezione intercettata e si interrompe il programma.
