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<=champ1 أبدًا، فسيتم استخدام معاملات السطر الأخير. وهنا:

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
    # نصف حصة إضافية إذا كان عدد الأطفال 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)
    # استرجاع الحقول الثلاثة «متزوج:أطفال:راتب» التي تشكل السطر
    (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)
    # إنشاء القوائم الثلاث - نفترض أن الأسطر صحيحة من الناحية النحوية
    # -- السطر 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
    # نصف حصة إضافية إذا كان عدد الأطفال 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)
    # استرجاع الحقول الثلاثة «متزوج:أطفال:راتب» التي تشكل السطر
    (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")
  
    # يتم إنشاء القوائم الثلاث - بافتراض أن الأسطر صحيحة من الناحية النحوية
    # -- السطر 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: يتم عرض رسالة الخطأ الخاصة بالاستثناء الذي تم اعتراضه وإيقاف البرنامج.