Skip to content

4. تمرین عملی – [IMPOTS]

4.1. مسئله

هدف ما نوشتن برنامه‌ای برای محاسبه بدهی مالیاتی یک مؤدی است. ما مورد ساده‌شده‌ای را در نظر می‌گیریم که مؤدی تنها حقوق خود را برای اظهار دارد:

  • ما تعداد طبقات مالیاتی کارمند را به صورت nbParts = nbEnfants/2 + 1 در صورتی که متأهل نباشد، محاسبه می‌کنیم، nbEnfants/2 + 2 اگر متأهل باشند، که در آن nbEnfants تعداد فرزندانشان است؛
  • درآمد مشمول مالیات او R به صورت R = 0.72 * S محاسبه می‌شود، که در آن S حقوق سالانه او است؛
  • ضریب خانوادگی او Q به صورت 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

هر سطر دارای ۳ فیلد است. برای محاسبه مالیات I، به دنبال اولین سطری می‌گردیم که QFfield1 باشد. برای مثال، اگر QF = 30000 باشد، سطر زیر را پیدا خواهیم کرد:

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):
    # در صورت وجود، نشانگر پایان خط را حذف کنید
    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
    # نیم سهم اضافی در صورت وجود حداقل ۳ فرزند
    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)
    # استخراج سه فیلد «married:children:salary» که خط را تشکیل می‌دهند
    (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)
    #ایجاد سه لیست – فرض می‌شود خطوط از نظر نحوی صحیح هستند
    #-- خط ۱
    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])
    # -- خط ۲
    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])
    #-- خط ۳
    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
    # نیم سهم اضافی در صورت وجود حداقل ۳ فرزند
    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)
    # استخراج سه فیلد «married:children:salary» که خط را تشکیل می‌دهند
    (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")
  
    # ایجاد سه لیست – فرض می‌شود که خطوط از نظر نحوی صحیح هستند
    #-- خط ۱
    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])
    #-- خط ۲
    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])
    #-- خط ۳
    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)
  • خط ۴: ما بررسی نمی‌کنیم که آیا فایل باز نمی‌شود. اگر باز نشود، یک استثنای IOError پرتاب می‌شود. ما اجازه می‌دهیم این استثنا به برنامه فراخواننده منتقل شود؛
  • خطوط ۹–۱۰: یک استثنا پرتاب می‌شود تا نشان دهد که اولین خط مورد انتظار وجود ندارد. از یک استثنای از پیش تعریف‌شده، 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()

# خواندن داده‌ها
...
  • خطوط ۱۲–۱۷: ما متد getImpots را فراخوانی می‌کنیم و دو استثناء را که ممکن است پرتاب کند، مدیریت می‌کنیم: IOError و RuntimeError. در این مدیریت، ما صرفاً متوجه می‌شویم که یک خطا رخ داده است؛
  • خطوط ۲۰–۲۲: پیام خطا برای استثناء ضبط‌شده نمایش داده می‌شود و برنامه خاتمه می‌یابد.