Skip to content

4. 应用练习 – [税费计算]

4.1. 题目

我们的目标是编写一个程序来计算纳税人的税额。我们考虑一种简化情况,即纳税人仅需申报工资收入:

  • 若纳税人未婚,则计算其适用税率档次数 nbParts = nbChildren / 2 + 1;若已婚,则为 nbChildren / 2 + 2,其中 nbChildren 表示子女数量;
  • 计算其应税收入 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 = 30,000,则找到的行将是:

24740 0.15 2072.5

此时税款 I 等于 0.15*R - 2072.5*nbParts。如果 QF 值导致条件 QF<=field1 永远无法满足,则使用最后一行中的系数。具体如下:

0 0.65 49062

由此得出税款 I = 0.65*R - 49062*nbParts。

4.2. 列表版本


程序 (impots_01)

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

import math, sys

def cutNewLineChar(ligne):
    #  delete the end-of-line mark if it exists
    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):
    #  married: yes, no
    #  children: number of children
    #  salary: annual salary

    #  number of shares
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    #  an additional 1/2 share if at least 3 children
    if enfants>=3:
        nbParts+=0.5
    #    taxable income
    revenuImposable=0.72*salaire
    #    family quotient
    quotient=revenuImposable/nbParts
    #  is set at the end of the limit table to stop the following loop
    limites[len(limites)-1]=quotient
    #  tAX CALCULATION
    i=0
    while(quotient>limites[i]):
        i=i+1
    #  because we've placed quotient at the end of the limit array, the previous loop
    #  cannot go beyond the limit table
    #  now we can calculate the tax
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


#    ------------------------------------------------ main
#    definition of constants
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]

#    reading data
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

#    open results file
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

#  use the current line of the data file
ligne=data.readline()
while(ligne != ''):
    #  remove any end-of-line marker
    ligne=cutNewLineChar(ligne)
    #  we retrieve the 3 fields married:children:salary which form the line
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    #  tax calculation
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    #  enter the result
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    #  a new line is read
    ligne=data.readline()
#    close files
data.close()
resultats.close()

结果

数据文件 data.txt

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

包含结果的 results.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

程序 (taxes_02)

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

import math,sys

# --------------------------------------------------------------------------
def getTables(IMPOTS):
    #  IMPOTS: the name of the file containing data from the limit tables, coeffR, coeffN
    #  does the IMPOTS file exist?
    try:
        data=open(IMPOTS,"r")
    except:
        return ("Le fichier IMPOTS n'existe pas",0,0,0)
    #  create the 3 lists - assume the lines are syntactically correct
    #  -- line 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])
    #  -- line 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])
    #  -- line 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])
    #    end
    return ("",limites,coeffR,coeffN)

# --------------------------------------------------------------------------
def cutNewLineChar(ligne):
    #  delete the end-of-line mark if it exists
    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):
    #  married: yes, no
    #  children: number of children
    #  salary: annual salary

    #  number of shares
    marie=marie.lower()
    if(marie=="oui"):
        nbParts=float(enfants)/2+2
    else:
        nbParts=float(enfants)/2+1
    #  an additional 1/2 share if at least 3 children
    if enfants>=3:
        nbParts+=0.5
    #    taxable income
    revenuImposable=0.72*salaire
    #    family quotient
    quotient=revenuImposable/nbParts
    #  is set at the end of the limit array to stop the loop that follows
    limites[len(limites)-1]=quotient
    #  tAX CALCULATION
    i=0
    while(quotient>limites[i]):
        i=i+1
    #  because we've placed quotient at the end of the limit array, the previous loop
    #  cannot exceed the limits of the board
    #  now we can calculate the tax
    return math.floor(revenuImposable*coeffR[i]-nbParts*coeffN[i])


#    ------------------------------------------------ main
#    definition of constants
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

#  the data required to calculate the tax has been placed in the IMPOTS file
#  one line per table in the form
#    val1:val2:val3,...
(erreur,limites,coeffR,coeffN)=getTables(IMPOTS)

#    was there a mistake?
if(erreur):
    print "{0}\n".format(erreur)
    sys.exit()

#    reading data
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

#    open results file
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

#  use the current line of the data file
ligne=data.readline()
while(ligne != ''):
    #  remove any end-of-line marker
    ligne=cutNewLineChar(ligne)
    #  we retrieve the 3 fields married:children:salary which form the line
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    #  tax calculation
    impot=calculImpots(marie,enfants,salaire,limites,coeffR,coeffN)
    #  enter the result
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    #  a new line is read
    ligne=data.readline()
#    close files
data.close()
resultats.close()

结果

与之前相同。


程序 (taxes_02b)

上面的 getImpots 方法(第 6–36 行)返回一个元组 (error, limits, coeffR, coeffN),其中 error 是一个错误消息,该消息可能为空。您可能希望使用异常来处理这些错误情况。在这种情况下:

  • 如果发生错误,getImpots 方法会抛出异常;
  • 否则,它将返回元组 (limits, coeffR, coeffN)。

因此,getImpots 方法的代码如下:

def getTables(IMPOTS):
    #  IMPOTS: the name of the file containing data from the limit tables, coeffR, coeffN
    #  does file IMPOTS exist? if not, exception IOError is thrown in this case
    data=open(IMPOTS,"r")

    #  create the 3 lists - assume the lines are syntactically correct
    #  -- line 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])
    #  -- line 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])
    #  -- line 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])
    #    end
    return (limites,coeffR,coeffN)
  • 第 4 行:我们未检查文件打开是否失败。若失败,将引发 IOError 异常。我们让该异常传播至调用程序;
  • 第 9–10 行:我们抛出一个异常,以指示预期中的第一行缺失。我们使用预定义的 RuntimeError 异常。我们也可以创建自己的异常类。稍后我们会这样做;
  • 第 16–17 行和第 23–24 行:我们对第 2 行和第 3 行也进行了同样的处理。

主程序代码如下:


# ------------------------------------------------ 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
...
  • 第 12–17 行:我们调用 getImpots 方法,并处理它可能抛出的两个异常:IOErrorRuntimeError。在此处理中,我们仅记录发生了错误;
  • 第 20–22 行:我们显示捕获到的异常的错误信息,并终止程序。