8. 应用练习 – 版本 1
8.1. 问题
上表使我们能够计算仅需申报工资收入的纳税人的简化税额。如注释(1)所示,按此方式计算的税额是在应用以下三项机制之前得出的:
- 适用于高收入者的家庭商数上限;
- 适用于低收入群体的税收抵免和减税;
因此,税额计算涉及以下步骤 [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

我们建议编写一个程序,用于计算仅需申报工资收入的纳税人的税款(简化情况):
8.1.1. 应纳税额的计算
应纳税额可按以下方式计算:
首先,计算纳税人的股份数:
- 每位父母各贡献1份;
- 前两名子女各贡献1/2股;
- 后续子女每人各贡献1股:
因此,股份总数为:
- nbParts=1+nbChildren*0.5+(nbChildren-2)*0.5(若员工未婚);
- 若已婚,则 nbParts=2+nbChildren*0.5+(nbChildren-2)*0.5;
- 我们计算应税收入 R = 0.9 * S,其中 S 为年薪;
- 家庭商 QF 按 QF = R / nbParts 计算;
- 根据以下数据(2019年),我们计算应纳税额 I:
9964 | 0 | 0 |
27,519 | 0.14 | 1,394.96 |
73,779 | 0.3 | 5,798 |
156,244 | 0.4 | 13,913.69 |
0 | 0.45 | 20163.45 |
每行包含 3 个字段:field1、field2、field3。要计算税款 I,我们找出满足 QF <= field1 的第一行,并取该行的数值。例如,对于一名已婚员工,有两个孩子,年薪 S 为 50,000 欧元:
应税收入:R=0.9*S=45,000
份额数:nbParts=2+2*0.5=3
家庭商:QF = 45,000 / 3 = 15,000
满足 QF <= field1 的第一行如下:
因此,税款 I 等于 0.14*R – 1394.96*股数=[0.14*45000-1394.96*3]=2115。税款四舍五入至最接近的欧元。
如果第一行满足条件 QF <= field1,则税额为零。
如果 QF 的取值导致条件 QF <= field1 永远无法满足,则使用最后一行中的系数。此处:
由此可得总税额 I = 0.45*R – 20163.45*nbParts。
8.1.2. 家族商数上限
为确定家庭商数(QF)上限是否适用,我们需重新计算不包含子女的应纳税额。再次以那位有两个子女、年薪S为50,000欧元的已婚雇员为例:
应税收入:R = 0.9 * S = 45,000
份额数:nbParts=2(子女不再计入)
家庭商数:QF = 45,000 / 2 = 22,500
满足 QF <= field1 的第一行如下:
因此,税款 I 等于 0.14*R – 1394.96*股数 = [0.14*45,000 – 1394.96*2] = 3,510。
最高子女相关福利:1551 × 2 = 3102 欧元
最低税额:3,510 – 3,102 = 408 欧元
按3个税率档次计算的应纳税额(已计算为2,115欧元)高于408欧元的最低税额,因此此处不适用家庭限额。
一般而言,税前税额大于 (tax1, tax2),其中:
- [税1]:包含子女计算的应纳税额;
- [税款2]:不计入子女且扣除与子女相关的最高抵免额(此处为每半份1,551欧元)后计算出的税款总额;
8.1.3. 减免额的计算

仍以一名已婚、育有两名子女且年薪S为50,000欧元的雇员为例:
上一步计算出的应纳税额(2,115)低于夫妇的2,627欧元(单身人士为1,595欧元):因此适用减免。其计算方法如下:
减免额 = 起征点(已婚夫妇 = 1,970 / 单身 = 1,196)- 0.75 * 税前税额
减免额 = 1,970 – 0.75 * 2,115 = 383.75,四舍五入后为384欧元。
新应纳税额 = 2,115 – 384 = 1,731 欧元
8.1.4. 减税额计算

当应纳税额低于特定门槛时,将对前文计算得出的应纳税额适用20%的减免。2019年的门槛如下:
- 单身:21,037欧元;
- 已婚夫妇:42,074欧元;(上文示例中使用的37,968欧元似乎有误);
该门槛值需增加以下数值:3,797 *(子女所贡献的半份份额数量)。
再次以那位有两个孩子、年薪S为50,000欧元的已婚雇员为例:
- 其应税收入(45,000欧元)低于门槛值(42,074 + 2 × 3,797)= 49,668欧元;
- 因此,他有权享受20%的减税:1,731 * 0.2 = 346.2欧元,四舍五入为347欧元;
- 纳税人的应纳税额为:1,731 – 347 = 1,384欧元;
8.1.5. 净税额计算
我们的计算到此结束:应缴税额为1,384欧元。实际上,纳税人可能还有资格享受其他扣除,特别是针对向公共或公益组织捐款的扣除。
8.1.6. 高收入人群
前面的例子适用于大多数雇员。然而,高收入者的税款计算方式有所不同。
8.1.6.1. 年收入10%减免的上限
在大多数情况下,应税收入按以下公式计算:R = 0.9 × S,其中S为年薪。这被称为10%的减免。该减免设有上限。2019年:
让我们以一名无子女的未婚雇员为例,其年薪为200,000欧元:
- 10%的减免额为200,000欧元 > 12,502欧元。因此,减免额上限为12,502欧元;
8.1.6.2. 家庭系数上限
让我们考虑一个适用第 |家庭系数上限| 节所述家庭上限的情况。以一对育有三个子女、年收入为100,000欧元的夫妇为例。让我们再次回顾计算步骤:
- 10%的扣除额为10,000欧元 < 12,502欧元。因此,应税收入R为100,000 - 10,000 = 90,000欧元;
- 该夫妇的份额数 nbParts = 2 + 0.5 × 2 + 1 = 4 份;
- 因此,其家庭商为 QF = R / nbParts = 90,000 / 4 = 22,500 欧元;
- 他们带子女的应纳税额 I1 为 I1 = 0.14 × 90,000 – 1,394.96 × 4 = 7,020 欧元;
- 其无子女的税款总额 I2:
- QF = 90,000 / 2 = 45,000 欧元;
- I2 = 0.3 × 90,000 – 5,798 × 2 = 15,404 欧元;
- 家庭商数上限规则规定,子女带来的减免额不得超过(1,551 × 4个半份额)= 6,204欧元。然而,此处I2 – I1 = 15,404 – 7,020 = 8,384欧元,大于6,204欧元;
- 因此,应纳税额重新计算为 I3 = I2 - 6,204 = 15,404 - 6,204 = 9,200 欧元;
这对夫妇既无法获得税收抵免,也无法享受减免,其最终应纳税额为9,200欧元。
8.1.7. 官方数据
税款计算较为复杂。本文档中的计算均基于以下示例。结果来源于税务机关的模拟器 |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:
纳税人 | 官方结果 | 本文算法计算结果 |
一对夫妇,育有2名子女,年收入55,555欧元 | 税额 = 2,815欧元 税率 = 14% | 税额 = 2,814 欧元 税率 = 14% |
一对夫妇,育有2名子女,年收入为50,000欧元( ) | 税额 = 1,385 欧元 税收抵免 = 720欧元 减免 = 0 欧元 税率 = 14% | 应纳税额 = 1,384欧元 折扣 = 384 欧元 抵免额 = 347 欧元 税率 = 14% |
一对夫妇,育有3个孩子,年收入50,000欧元 | 税额 = 0 欧元 税收抵免 = 384 欧元 减免额 = 346 欧元 税率 = 14% | 应纳税额 = 0欧元 折扣=720欧元 扣除额=0欧元 税率 = 14% |
单身,有2个孩子,年收入100,000欧元 | 应缴税额 = 19,884欧元 税收抵免 = 0 欧元 扣除额 = 0 欧元 税率 = 41% | 应纳税额 = 19,884欧元 附加费 = 4,480 欧元 折扣 = 0 欧元 减免 = 0 欧元 税率 = 41% |
单身,育有3名子女,年收入100,000欧元 | 应纳税额 = 16,782 欧元 税收抵免=0欧元 扣除额 = 0 欧元 税率 = 41% | 应纳税额 = 16,782欧元 附加费 = 7,176 欧元 折扣=0欧元 减免 = 0 欧元 税率 = 41% |
一对夫妇,育有3名子女,年收入100,000欧元 | 应缴税款 = 9,200 欧元 税收抵免=0欧元 扣除额 = 0 欧元 税率 = 30% | 应纳税额 = 9,200 欧元 附加费 = 2,180 欧元 折扣=0欧元 减免 = 0 欧元 税率 = 30% |
一对夫妇,育有5个孩子,年收入100,000欧元 | 应缴税款 = 4,230 欧元 税收抵免=0欧元 扣除额 = 0 欧元 税率 = 14% | 应纳税额 = 4,230 欧元 折扣 = 0 欧元 扣除额=0欧元 税率 = 14% |
单身,无子女,年收入100,000欧元 | 应纳税额 = 22,986 欧元 税收抵免 = 0 欧元 扣除额 = 0 欧元 税率 = 41% | 应纳税额 = 22,986 欧元 附加费 = 0 欧元 折扣 = 0 欧元 减免 = 0 欧元 税率 = 41% |
一对夫妇,育有两名子女,年收入为30,000欧元 | 应纳税额 = 0 欧元 税收抵免 = 0 欧元 扣除额 = 0 欧元 税率 = 0% | 应纳税额 = 0 欧元 折扣 = 0 欧元 减免=0欧元 税率 = 0% |
单身无子女,年收入200,000欧元 | 应纳税额 = 64,211 欧元 税收抵免=0欧元 扣除额 = 0 欧元 税率 = 45% | 应纳税额 = 64,210欧元 附加费 = 7,498 欧元 折扣=0欧元 减免 = 0 欧元 税率 = 45% |
一对夫妇,育有3名子女,年收入200,000欧元 | 应纳税额 = 42,843 欧元 税收抵免=0欧元 扣除额 = 0 欧元 税率 = 41% | 应纳税额 = 42,842欧元 附加费 = 17,283 欧元 折扣=0欧元 减免 = 0 欧元 税率 = 41% |
在上例中,“附加费”是指高收入者因以下两个因素而需额外支付的金额:
由于税务机关的模拟器未提供该数据,因此无法核实此指标。
我们可以看到,该文档的算法每次都能计算出正确的税额,尽管存在1欧元的误差。这种误差源于四舍五入。在某些情况下,所有金额会被四舍五入至最接近的整数欧元,而在其他情况下则会四舍五入至最接近的整数欧元。由于我不熟悉官方规则,因此文档算法中的金额进行了如下四舍五入:
- 折扣和减免金额向上取整至最接近的欧元;
- 附加费和最终税额则向下舍入至最接近的欧元;
我们将开发多个版本的税费计算应用程序。
8.2. 版本 1

8.2.1. 主脚本
我们提供一个初始程序,其中:
- 计算税款所需的数据以列表和常量的形式硬编码在代码中;
- 纳税人数据(已婚、子女、工资)存储在第一个文本文件 [taxpayersdata.txt] 中;
- 税款计算结果(婚姻状况、子女数、工资、税额)存储在第二个文本文件 [results.txt] 中;
脚本 [v-01/main.py] 如下:
| # modules
import sys
from impots.v01.shared.impôts_module_01 import *
# hand -----------------------
# constants
# taxpayer file
DATA = "./data/taxpayersdata.txt"
# results file
RESULTATS = "./data/résultats.txt"
try:
# reading taxpayer data
tax_payers = get_taxpayers_data(DATA)
# results list
results = []
# taxpayers' taxes are calculated
for tax_payer in tax_payers:
# tax calculation returns a dictionary of keys
# ['married', 'children', 'salary', 'tax', 'surcôte', 'décôte', 'réduction', 'taux']
result = calcul_impôt(tax_payer['marié'], tax_payer['enfants'], tax_payer['salaire'])
# the dictionary is added to the list of results
results.append(result)
# we record the results
record_results(RESULTATS, results)
except BaseException as erreur:
# there may be various errors: no file, incorrect file content
# display the error and exit the application
print(f"l'erreur suivante s'est produite : {erreur}]\n")
sys.exit()
|
注释
- 第 4 行:我们使用模块 [impots.v01.modules.impôts_module_01]。请注意,此路径是相对于 PyCharm 项目根目录的;
- 第 10 行:文件 [data/taxpayersdata.txt] 内容如下:
| oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000
|
每行代表一个包含三个元素的元组 [是否已婚或处于民事伴侣关系、子女数量、年薪(单位:欧元)]。
- 第12行:用于存放文件[taxpayersdata.txt]中每位纳税人税款计算结果的文件。该文件将包含以下内容:
| {'marié': 'oui', 'enfants': 2, 'salaire': 55555, 'impôt': 2814, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'oui', 'enfants': 2, 'salaire': 50000, 'impôt': 1384, 'surcôte': 0, 'décôte': 384, 'réduction': 347, 'taux': 0.14}
{'marié': 'oui', 'enfants': 3, 'salaire': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
|
- 第 16 行:我们读取 [taxpayersdata.txt] 中包含的纳税人数据。我们获取一个键为 [已婚, 子女, 工资] 的字典列表,每个字典代表一名纳税人;
- 第17–25行:计算[taxPayers]列表中纳税人的税额。返回一个[results]列表,其中每个元素仍是键值对为[已婚, 子女, 工资, 税额, 附加费, 折扣, 减免, 税率]的字典;
- 第 27 行:将 [results] 列表按上述格式保存到文件 [results.txt] 中;
- 第 28–32 行:捕获模块 [impots.v01.modules.impôts_module_01] 可能抛出的所有异常;
接下来我们将详细说明 [main] 脚本中使用的三个函数:
- [get_taxpayers_data]:用于读取纳税人数据;
- [calcul_impôt]:用于计算纳税人的税款;
- [record_results]:将结果保存到文本文件中;
所有这些函数都位于 [impots.modules.impôts_module_01] 模块中。
8.2.2. [impots.v01.shared.impôts_module_01] 模块
用于税款计算的函数已归类到 [impots.v01.shared.impôts_module_01] 模块中:

- 在 [1] 中:定义税费计算常量;
- 在 [2] 中:模块中的函数列表;
8.2.3. 函数 [get_taxpayers_data]
[get_taxpayers_data] 函数如下:
| # imports
import codecs
…
# reading taxpayer data
# ----------------------------------------
def get_taxpayers_data(taxpayers_filename: str) -> list:
# reading taxpayer data
file = None
try:
# list of taxpayers
taxpayers = []
# open file
file = codecs.open(taxpayers_filename, "r", "utf8")
# read the first line of the taxpayer file
ligne = file.readline().strip()
# as long as there's a line left to operate
while ligne != '':
# we retrieve the 3 fields married,children,salary which form the line
(marié, enfants, salaire) = ligne.split(",")
# we add them to the list of taxpayers
taxpayers.append({'marié': marié.strip().lower(), 'enfants': int(enfants), 'salaire': int(salaire)})
# a new line is read from the taxpayer file
ligne = file.readline().strip()
# we return the result
return taxpayers
finally:
# close the file if it has been opened
if file:
file.close()
|
注释
- 第 7 行:[taxpayers_filename] 是要处理的文件名。该函数返回一个列表;
- 第 18–24 行:循环处理文本文件中的 [married, children, salary] 行;
- 第 20 行:提取该行的三个元素。此处假设该行语法正确,即确实包含预期的三个元素;
- 第 22 行:构建一个键为 [married, children, salary] 的字典,并将该字典添加到 [taxPayers] 列表中;
- 第 26 行:文件处理完成后,返回 [taxPayers] 列表;
- 第 10–30 行:请注意,第 10 行的 [try] 代码块中未添加 [catch] 子句。[catch] 子句并非强制要求。在第 27 行,添加了 [finally] 子句,用于在所有情况下(无论是否发生错误)关闭文本文件;
- 这种 try/finally 结构允许潜在的异常逸出(因为没有 catch)。该异常将传播到主脚本 [main],主脚本将停止运行并显示该异常(参见 |主脚本| 部分)。该机制已被用于该模块的大多数函数;
8.2.4. [calcul_impôt] 函数
[calcul_impôt] 函数如下:
| # imports
import codecs
import math
# 2019 tax brackets
limites = [9964, 27519, 73779, 156244, 0]
coeffr = [0, 0.14, 0.3, 0.41, 0.45]
coeffn = [0, 1394.96, 5798, 13913.69, 20163.45]
# constant for 2019 tax calculation
PLAFOND_QF_DEMI_PART = 1551
PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION = 21037
PLAFOND_REVENUS_COUPLE_POUR_REDUCTION = 42074
VALEUR_REDUC_DEMI_PART = 3797
PLAFOND_DECOTE_CELIBATAIRE = 1196
PLAFOND_DECOTE_COUPLE = 1970
PLAFOND_IMPOT_COUPLE_POUR_DECOTE = 2627
PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE = 1595
ABATTEMENT_DIXPOURCENT_MAX = 12502
ABATTEMENT_DIXPOURCENT_MIN = 437
…
# tAX CALCULATION
# ----------------------------------------
def calcul_impôt(marié: str, enfants: int, salaire: int) -> dict:
# married: yes, no
# children: number of children
# salary: annual salary
# limits, coeffr, coeffn: data tables for tax calculation
#
# tax calculation with children
result1 = calcul_impôt_2(marié, enfants, salaire)
impot1 = result1["impôt"]
# tax calculation without children
if enfants != 0:
result2 = calcul_impôt_2(marié, 0, salaire)
impot2 = result2["impôt"]
# application of the family allowance ceiling
if enfants < 3:
# PLAFOND_QF_DEMI_PART euros for the first 2 children
impot2 = impot2 - enfants * PLAFOND_QF_DEMI_PART
else:
# PLAFOND_QF_DEMI_PART euros for the first 2 children, double for subsequent children
impot2 = impot2 - 2 * PLAFOND_QF_DEMI_PART - (enfants - 2) * 2 * PLAFOND_QF_DEMI_PART
else:
impot2 = impot1
result2 = result1
# we take the highest tax with the rate and surcharge that go with it
if impot1 > impot2:
impot = impot1
taux = result1["taux"]
surcôte = result1["surcôte"]
else:
surcôte = impot2 - impot1 + result2["surcôte"]
impot = impot2
taux = result2["taux"]
# calculation of any discount
décôte = get_décôte(marié, salaire, impot)
impot -= décôte
# calculation of any tax reduction
réduction = get_réduction(marié, salaire, enfants, impot)
impot -= réduction
# result
return {"marié": marié, "enfants": enfants, "salaire": salaire, "impôt": math.floor(impot), "surcôte": surcôte,
"décôte": décôte, "réduction": réduction, "taux": taux}
|
注释
- 第6–8行:税率区间(参见“总税额计算”一节);
- 第11–20行:税额计算的常量;
- 请注意,第5–20行初始化的元素对我们即将描述的函数而言是全局的。因此,只要使用它们的函数未声明同名变量,这些元素就始终有效;
- 第 5–20 行中的数值每年都会变化。此处采用的是 2019 年的数据;
- 第25行:[calculate_tax]函数接受三个参数:
- [married]:是/否,表示纳税人是否已婚或处于民事伴侣关系;
- [children]:子女数量;
- [salary]:其年薪(单位为欧元);
- 第31–33行:考虑子女因素的税额计算;
- 第34–47行:这些行实现了家庭商数的上限(参见|家庭商数上限|章节);
- 第49–57行:这些行用于计算纳税人的税率以及任何附加税(参见“高收入情况”部分);
- 第59–61行:计算任何税收抵免(参见章节 |税收抵免的计算|);
- 第62–64行:计算应纳税额的减免(参见“税额减免的计算”一节);
该算法相当复杂,我们不会比注释中提供的内容更深入地探讨。该算法实现了|问题|一节中描述的税款计算方法。
8.2.5. [calcul_tax_2] 函数
函数 [calcul_impôt] 调用以下函数 [calcul_impôt_2]:
| def calcul_impôt_2(marié: str, enfants: int, salaire: int) -> list:
# married: yes, no
# children: number of children
# salary: annual salary
# limits, coeffr, coeffn: data tables for tax calculation
#
# number of shares
marié = marié.strip().lower()
if marié == "oui":
nb_parts = enfants / 2 + 2
else:
nb_parts = enfants / 2 + 1
# 1 part per child from the 3rd
if enfants >= 3:
# an additional half share for each child from the 3rd onwards
nb_parts += 0.5 * (enfants - 2)
# taxable income
revenu_imposable = get_revenu_imposable(salaire)
# surcharge
surcôte = math.floor(revenu_imposable - 0.9 * salaire)
# for rounding problems
if surcôte < 0:
surcôte = 0
# family quotient
quotient = revenu_imposable / nb_parts
# 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 += 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
impôt = math.floor(revenu_imposable * coeffr[i] - nb_parts * coeffn[i])
# result
return {"impôt": impôt, "surcôte": surcôte, "taux": coeffr[i]}
|
该算法在第 8.1.1 节中进行了描述。
8.2.6. [get_discount] 函数
[get_discount] 函数实现了任何税收折扣的计算(参见 |折扣计算| 章节):
| # calculates any discount
def get_décôte(marié: str, salaire: int, impots: int) -> int:
# at the outset, a zero discount
décôte = 0
# maximum tax amount to qualify for discount
plafond_impôt_pour_décôte = PLAFOND_IMPOT_COUPLE_POUR_DECOTE if marié == "oui" else PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE
if impots < plafond_impôt_pour_décôte:
# maximum discount
plafond_décôte = PLAFOND_DECOTE_COUPLE if marié == "oui" else PLAFOND_DECOTE_CELIBATAIRE
# theoretical discount
décôte = plafond_décôte - 0.75 * impots
# the discount cannot exceed the amount of tax due
if décôte > impots:
décôte = impots
# no discount <0
if décôte < 0:
décôte = 0
# result
return math.ceil(décôte)
|
8.2.7. [get_reduction] 函数
[get_reduction] 函数实现了任何税收减免的计算(参见 |税收减免的计算| 章节):
| # calculates any reduction
def get_réduction(marié: str, salaire: int, enfants: int, impots: int) -> int:
# the income ceiling to qualify for the 20% reduction
plafond_revenu_pour_réduction = PLAFOND_REVENUS_COUPLE_POUR_REDUCTION if marié == "oui" else PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION
plafond_revenu_pour_réduction += enfants * VALEUR_REDUC_DEMI_PART
if enfants > 2:
plafond_revenu_pour_réduction += (enfants - 2) * VALEUR_REDUC_DEMI_PART
# taxable income
revenu_imposable = get_revenu_imposable(salaire)
# reduction
réduction = 0
if revenu_imposable < plafond_revenu_pour_réduction:
# 20% discount
réduction = 0.2 * impots
# result
return math.ceil(réduction)
|
8.2.8. [get_taxable_income] 函数
[get_taxable_income] 函数根据年薪计算应税收入:
| # revenu_imposable = salaireAnnuel - allowance
# the allowance has a minimum and a maximum
# ----------------------------------------
def get_revenu_imposable(salaire: int) -> int:
# 10% salary deduction
abattement = 0.1 * salaire
# this allowance may not exceed ABATTEMENT_DIXPOURCENT_MAX
if abattement > ABATTEMENT_DIXPOURCENT_MAX:
abattement = ABATTEMENT_DIXPOURCENT_MAX
# the allowance cannot be less than ABATTEMENT_DIXPOURCENT_MIN
if abattement < ABATTEMENT_DIXPOURCENT_MIN:
abattement = ABATTEMENT_DIXPOURCENT_MIN
# taxable income
revenu_imposable = salaire - abattement
# result
return math.floor(revenu_imposable)
|
8.2.9. [record_results] 函数
[record_results] 函数将税款计算结果保存到文本文件中:
| # writing results to a text file
# ----------------------------------------
def record_results(results_filename: str, results: list):
# results_filename: the name of the text file in which to place the results
# results: the results list in the form of a dictionary list
# each dictionary is written on a line of text
résultats = None
try:
# opening the results file
résultats = codecs.open(results_filename, "w", "utf8")
# taxpayer exploitation
for result in results:
# enter the result in the results file
résultats.write(f"{result}\n")
# next taxpayer
finally:
# close the file if it has been opened
if résultats:
résultats.close()
|
8.2.10. 结果
如前所述,使用以下纳税人文件 [taxpayersdata.txt]:
| oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000
|
脚本 [main.py] 会生成以下文件 [results.txt]:
| {'marié': 'oui', 'enfants': 2, 'salaire': 55555, 'impôt': 2814, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'oui', 'enfants': 2, 'salaire': 50000, 'impôt': 1384, 'surcôte': 0, 'décôte': 384, 'réduction': 347, 'taux': 0.14}
{'marié': 'oui', 'enfants': 3, 'salaire': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
|
这些结果与“官方数据”部分中的官方数据一致。
现在,让我们在控制台窗口中运行此版本:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01>python main.py
Traceback (most recent call last):
File "main.py", line 4, in <module>
from impots.v01.shared.impôts_module_01 import *
ModuleNotFoundError: No module named 'impots'
我们遇到了一个以前见过的错误:无法找到某个模块,本次是 [impots] 模块。请记住,这意味着:
- Python 解释器已逐一搜索了 Python 路径中的所有目录;
- 但在这些目录中,均未找到包含 [impots.py] 脚本的目录;
版本 [v02] 将提供此问题的解决方案。