4. Ćwiczenie praktyczne – [IMPOTS]
![]() |
4.1. Zadanie
Zadaniem jest napisanie programu umożliwiającego obliczenie podatku podatnika. Rozważamy uproszczony przypadek podatnika, który ma do zadeklarowania wyłącznie swoje wynagrodzenie:
- liczy się liczbę udziałów pracownika według wzoru nbParts = nbEnfants/2 + 1, jeśli nie jest żonaty, nbEnfants/2 + 2, jeśli jest żonaty, gdzie nbEnfants to liczba jego dzieci;
- oblicza się jego dochód podlegający opodatkowaniu R = 0,72 * S, gdzie S to jego roczne wynagrodzenie;
- oblicza się jego współczynnik rodzinny Q = R/N;
- oblicza się jego podatek I na podstawie poniższych danych.
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
Każdy wiersz zawiera 3 pola. Aby obliczyć podatek I, należy znaleźć pierwszy wiersz, w którym QF <= pole1. Na przykład, jeśli QF = 30000, znajdziemy wiersz:
Podatek I wynosi wówczas 0,15*R – 2072,5*nbParts. Jeśli QF jest takie, że relacja QF <= pole1 nigdy nie jest spełniona, wówczas stosuje się współczynniki z ostatniego wiersza. W tym przypadku:
co daje podatek I = 0,65*R – 49062*nbParts.
4.2. Wersja z listami
# -*- coding=utf-8 -*-
import math, sys
def cutNewLineChar(ligne):
# usuwanie znacznika końca wiersza, jeśli istnieje
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):
# stan cywilny: tak, nie
# dzieci: liczba dzieci
# wynagrodzenie: roczne wynagrodzenie
# liczba udziałów
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# o 1/2 udziału więcej, jeśli ma co najmniej 3 dzieci
if enfants>=3:
nbParts+=0.5
# dochód podlegający opodatkowaniu
revenuImposable=0.72*salaire
# współczynnik rodzinny
quotient=revenuImposable/nbParts
# umieszczony na końcu tabeli limitów w celu zakończenia następującej pętli
limites[len(limites)-1]=quotient
# obliczenie podatku
i=0
while(quotient>limites[i]):
i=i+1
# ponieważ iloraz rodzinny umieszczono na końcu tablicy limitów, poprzednia pętla
# nie może wykraczać poza tablicę limitów
# teraz można obliczyć podatek
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ main
# definicja stałych
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]
# odczyt danych
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# otwarcie pliku wyników
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# przetwarzamy bieżący wiersz pliku danych
ligne=data.readline()
while(ligne != ''):
# usuwanie ewentualnego znaku końca wiersza
ligne=cutNewLineChar(ligne)
# pobieranie trzech pól: „żonaty:dzieci:wynagrodzenie”, które tworzą wiersz
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# obliczamy podatek
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# zapisuje się wynik
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# odczytuje się nowy wiersz
ligne=data.readline()
# zamykamy pliki
data.close()
resultats.close()
Plik danych data.txt:
Pliki resultats.txt zawierające uzyskane wyniki:
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. Wersja z plikami tekstowymi
W poprzednim przykładzie dane niezbędne do obliczenia podatku pochodziły z trzech list. Teraz będą one pobierane z pliku tekstowego:
# -*- coding=utf-8 -*-
import math,sys
# --------------------------------------------------------------------------
def getTables(IMPOTS):
# IMPOTS: nazwa pliku zawierającego dane z tabel limitów, coeffR, coeffN
# czy plik IMPOTS istnieje?
try:
data=open(IMPOTS,"r")
except:
return ("Le fichier IMPOTS n'existe pas",0,0,0)
# utworzenie trzech list – zakłada się, że wiersze są poprawne pod względem składniowym
# — wiersz 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])
# — wiersz 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])
# — wiersz 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])
# koniec
return ("",limites,coeffR,coeffN)
# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
# usuwamy znacznik końca wiersza, jeśli występuje
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):
# stan cywilny: tak, nie
# dzieci: liczba dzieci
# wynagrodzenie: roczne wynagrodzenie
# liczba udziałów
marie=marie.lower()
if(marie=="oui"):
nbParts=float(enfants)/2+2
else:
nbParts=float(enfants)/2+1
# o 1/2 udziału więcej, jeśli ma co najmniej 3 dzieci
if enfants>=3:
nbParts+=0.5
# dochód podlegający opodatkowaniu
revenuImposable=0.72*salaire
# współczynnik rodzinny
quotient=revenuImposable/nbParts
# umieszczony na końcu tabeli limitów w celu zakończenia następującej pętli
limites[len(limites)-1]=quotient
# obliczenie podatku
i=0
while(quotient>limites[i]):
i=i+1
# ponieważ iloraz rodzinny umieszczono na końcu tablicy limitów, poprzednia pętla
# nie może wykraczać poza tablicę limitów
# teraz można obliczyć podatek
return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])
# ------------------------------------------------ main
# definicja stałych
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# dane niezbędne do obliczenia podatku zostały umieszczone w pliku IMPOTS
# w postaci jednego wiersza na tabelę w formacie
# val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)
# czy wystąpił błąd?
if(erreur):
print "{0}\n".format(erreur)
sys.exit()
# odczyt danych
try:
data=open(DATA,"r")
except:
print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
sys.exit()
# otwarcie pliku wyników
try:
resultats=open(RESULTATS,"w")
except:
print "Impossible de creer le fichier des résultats [RESULTATS]"
sys.exit()
# przetwarzanie bieżącego wiersza pliku danych
ligne=data.readline()
while(ligne != ''):
# usuwamy ewentualny znacznik końca wiersza
ligne=cutNewLineChar(ligne)
# pobieranie trzech pól: „żonaty:dzieci:wynagrodzenie”, które tworzą wiersz
(marie,enfants,salaire)=ligne.split(",")
enfants=int(enfants)
salaire=int(salaire)
# obliczamy podatek
impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
# zapisuje się wynik
resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
# odczytuje się nowy wiersz
ligne=data.readline()
# zamykamy pliki
data.close()
resultats.close()
Takie same jak poprzednio.
Powyższa metoda getImpots (wiersze 6–36) zwraca krotkę (erreur, limites, coeffR, coeffN), gdzie erreur to komunikat o błędzie, który może być pusty. Można rozważyć obsługę takich przypadków błędów za pomocą wyjątków. W takim przypadku:
- w przypadku błędu metoda getImpots zgłasza wyjątek;
- w przeciwnym razie zwraca krotkę (limites, coeffR, coeffN).
Kod metody getImpots wygląda wówczas następująco:
def getTables(IMPOTS):
# IMPOTS: nazwa pliku zawierającego dane z tabel limitów, coeffR, coeffN
# czy plik IMPOTS istnieje? Jeśli nie, to w tym przypadku zgłaszany jest wyjątek IOError
data=open(IMPOTS,"r")
# utworzenie trzech list – zakłada się, że wiersze są poprawne pod względem składniowym
# — wiersz 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])
# — wiersz 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])
# — wiersz 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])
# koniec
return (limites,coeffR,coeffN)
- wiersz 4: nie sprawdzamy, czy otwarcie pliku zakończyło się niepowodzeniem. Jeśli tak się stanie, zgłaszany jest wyjątek IOError. Pozwalamy, aby wyjątek ten został przekazany do programu wywołującego;
- wiersze 9–10: generujemy wyjątek, aby zasygnalizować brak pierwszego oczekiwanego wiersza. Wykorzystujemy predefiniowany wyjątek RuntimeError. Można również tworzyć własne klasy wyjątków. Zrobimy to nieco później;
- wiersze 16–17 i 23–24: powtarzamy tę samą procedurę dla wierszy 2 i 3.
Kod programu głównego wygląda wówczas następująco:
# ------------------------------------------------ main
# definicja stałych
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"
# dane niezbędne do obliczenia podatku zostały umieszczone w pliku IMPOTS
# w ilości jednego wiersza na tabelę w postaci
# val1:val2:val3,...
erreur=False
try:
(limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
erreur=True
except RuntimeError, message:
erreur=True
# czy wystąpił błąd?
if(erreur):
print "L'erreur suivante s'est produite : {0}\n".format(message)
sys.exit()
# odczyt danych
...
- wiersze 12–17: wywołujemy metodę getImpots i obsługujemy dwa wyjątki, które może ona wygenerować: IOError i RuntimeError. W ramach tej obsługi ograniczamy się do odnotowania, że wystąpił błąd;
- wiersze 20–22: wyświetla się komunikat o błędzie związany z przechwyconym wyjątkiem i kończy się działanie programu.
