Skip to content

4. Практичне завдання – [IMPOTS]

4.1. Задача

Задано написати програму, яка дозволяє обчислити податок платника податків. Розглянемо спрощений випадок, коли платник податків має лише одну заробітну плату, яку потрібно задекларувати:

  • розраховуємо кількість часткок працівника nbParts=nbEnfants/2 +1, якщо він не одружений, nbEnfants/2+2, якщо він одружений, де nbEnfants — кількість його дітей;
  • розраховується його оподатковуваний дохід R=0,72*S, де S — його річна заробітна плата;
  • розраховується його сімейний коефіцієнт Q = R/N;
  • розраховується його податок I на основі таких даних.
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

Кожен рядок має 3 поля. Щоб обчислити податок I, шукаємо перший рядок, у якому QF <= поле1. Наприклад, якщо QF = 30000, то знайдемо такий рядок:

24740 0.15 2072.5

Тоді податок I дорівнює 0,15*R - 2072,5*nbParts. Якщо QF є таким, що співвідношення QF <= поле1 ніколи не виконується, то використовуються коефіцієнти останнього рядка. У даному випадку:

0 0.65 49062

що дає податок I=0,65*R - 49062*nbParts.

4.2. Версія зі списками


Програма (impots_01)


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

import math, sys

def cutNewLineChar(ligne):
    # видалення позначки кінця рядка, якщо вона існує
    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):
    # одружений: так, ні
    # діти: кількість дітей
    # зарплата: річна зарплата

    # кількість часток
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    # на 1/2 частки більше, якщо є щонайменше 3 дітей
    if enfants>=3:
        nbParts+=0.5
    # оподатковуваний дохід
    revenuImposable=0.72*salaire
    # сімейний коефіцієнт
    quotient=revenuImposable/nbParts
    # вказується в кінці таблиці обмежень для припинення наступного циклу
    limites[len(limites)-1]=quotient
    # розрахунок податку
    i=0
    while(quotient>limites[i]):
        i=i+1
    # оскільки коефіцієнт розміщено в кінці таблиці граничних значень, попередній цикл
    # не може виходити за межі таблиці обмежень
    # тепер можна обчислити податок
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


# ------------------------------------------------ main
# визначення констант
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]

# читання даних
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

# відкриття файлу результатів
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

# обробка поточного рядка файлу даних
ligne=data.readline()
while(ligne != ''):
    # видалення можливого символу кінця рядка
    ligne=cutNewLineChar(ligne)
    # витягуються 3 поля «одружений:діти:зарплата», що утворюють рядок
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    # розраховується податок
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    # записуємо результат
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    # зчитується новий рядок
    ligne=data.readline()
# закриваються файли
data.close()
resultats.close()

Результати

Файл даних data.txt:

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Файли resultats.txt з отриманими результатами:

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. Версія з текстовими файлами

У попередньому прикладі дані, необхідні для розрахунку податку, містилися у трьох списках. Відтепер їх шукатимуть у текстовому файлі:

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

Програма (impots_02)


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

import math,sys

# --------------------------------------------------------------------------
def getTables(IMPOTS):
    # IMPOTS: ім’я файлу, що містить дані таблиць обмежень, coeffR, coeffN
    # Чи існує файл IMPOTS?
    try:
        data=open(IMPOTS,"r")
    except:
        return ("Le fichier IMPOTS n'existe pas",0,0,0)
    # створення 3 списків — припускаємо, що рядки синтаксично правильні
    # — рядок 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])
    # — рядок 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])
    # — рядок 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])
    # кінець
    return ("",limites,coeffR,coeffN)

# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
    # видаляємо позначку кінця рядка, якщо вона є
    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):
    # одружений: так, ні
    # діти: кількість дітей
    # зарплата: річна зарплата

    # кількість часток
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    # ще 1/2 частки, якщо є щонайменше 3 дітей
    if enfants>=3:
        nbParts+=0.5
    # оподатковуваний дохід
    revenuImposable=0.72*salaire
    # сімейний коефіцієнт
    quotient=revenuImposable/nbParts
    # вказується в кінці таблиці обмежень для припинення наступного циклу
    limites[len(limites)-1]=quotient
    # розрахунок податку
    i=0
    while(quotient>limites[i]):
        i=i+1
    # оскільки коефіцієнт розміщено в кінці таблиці граничних значень, попередній цикл
    # не може виходити за межі таблиці обмежень
    # тепер можна обчислити податок
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


# ------------------------------------------------ main
# визначення констант
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

# дані, необхідні для розрахунку податку, були занесені до файлу IMPOTS
# по одному рядку на таблицю у вигляді
# val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)

# Чи сталася помилка?
if(erreur):
    print "{0}\n".format(erreur)
    sys.exit()

# читання даних
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

# відкриття файлу результатів
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

# обробка поточного рядка файлу даних
ligne=data.readline()
while(ligne != ''):
    # видаляється можливий символ кінця рядка
    ligne=cutNewLineChar(ligne)
    # витягуються 3 поля «одружений:діти:зарплата», що утворюють рядок
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    # розраховується податок
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    # записуємо результат
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    # зчитується новий рядок
    ligne=data.readline()
# закриваємо файли
data.close()
resultats.close()

Результати

Такі самі, як і раніше.


Програма (impots_02b)

Вищезазначений метод getImpots (рядки 6–36) повертає кортеж (erreur, limites, coeffR, coeffN), де erreur — це повідомлення про помилку, яке може бути порожнім. Можливо, ці випадки помилок доцільно обробляти за допомогою винятків. У цьому випадку:

  • у разі помилки метод getImpots генерує виняток;
  • інакше вона повертає кортеж (limites, coeffR, coeffN).

Тоді код методу getImpots виглядає так:


def getTables(IMPOTS):
    # IMPOTS: ім'я файлу, що містить дані таблиць обмежень, coeffR, coeffN
    # чи існує файл IMPOTS? Якщо ні, то в цьому випадку генерується виняток IOError
    data=open(IMPOTS,"r")
  
    # створення 3 списків — припускається, що рядки синтаксично правильні
    # — рядок 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])
    # — рядок 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])
    # — рядок 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])
    # кінець
    return (limites,coeffR,coeffN)
  • рядок 4: не перевіряється, чи не відбулося помилки під час відкриття файлу. Якщо відкриття не вдалося, генерується виняток IOError. Цей виняток передається до програми, що викликає;
  • рядки 9–10: генерується виняток, щоб вказати, що перший очікуваний рядок відсутній. Використовується попередньо визначений виняток RuntimeError. Також можна створювати власні класи винятків. Ми зробимо це трохи пізніше;
  • рядки 16–17 та 23–24: те саме повторюємо для рядків 2 та 3.

Код головної програми тепер виглядає так:


# ------------------------------------------------ main
# визначення констант
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

# дані, необхідні для розрахунку податку, були розміщені у файлі IMPOTS
# по одному рядку на таблицю у вигляді
# val1:val2:val3,...

erreur=False
try:
    (limites,coeffR,coeffN)=getTables(IMPOTS)
except IOError, message:
    erreur=True
except RuntimeError, message:
    erreur=True

# Чи сталася помилка?
if(erreur):
    print "L'erreur suivante s'est produite : {0}\n".format(message)
    sys.exit()

# читання даних
...
  • рядки 12–17: викликаємо метод getImpots і обробляємо два винятки, які він може генерувати: IOError та RuntimeError. Під час цієї обробки ми лише фіксуємо, що сталася помилка;
  • рядки 20–22: виводимо повідомлення про помилку перехопленого винятку та зупиняємо програму.