13. الفئتان العامتان [BaseEntity] و [MyException]
سنقوم الآن بتعريف فئتين سنستخدمهما بانتظام في المستقبل.

13.1. فئة MyException
توفر فئة [MyException] (MyException.py) فئة استثناء مخصصة:
# une classe d'exception propriétaire dérivant de [BaseException]
class MyException(BaseException):
# constructeur
def __init__(self: object, code: int, message: str):
# parent
BaseException.__init__(self, message)
# code erreur
self.code = code
# toString
def __str__(self):
return f"MyException[{self.code}, {super().__str__()}]"
# getter
@property
def code(self) -> int:
return self.__code
# setter
@code.setter
def code(self, code: int):
# le code d'erreur doit être un entier positif
if isinstance(code, int) and code > 0:
self.__code = code
else:
# exception
raise BaseException(f"code erreur {code} incorrect")
ملاحظات
- السطر 2: فئة [MyException] مشتقة من فئة [BaseException] المحددة مسبقًا؛
- السطر 4: يقبل المنشئ معلمتين:
- [code]: رمز خطأ صحيح؛
- [message]: رسالة خطأ؛
- السطر 6: يتم تمرير رسالة الخطأ إلى الفئة الأصلية؛
- الأسطر 14-27: يتم الوصول إلى السمة [code] عبر أداة الحصول/التعيين؛
- السطران 23-24: يتم التحقق من صحة السمة [code]: يجب أن تكون عددًا صحيحًا أكبر من 0؛
13.2. فئة [BaseEntity]
ستكون فئة [BaseEntity] هي الفئة الأصلية لمعظم الفئات التي ننشئها لتغليف المعلومات حول كائن ما. من الآن فصاعدًا، سنستخدم بشكل أساسي نوعين من الفئات:
- الفئات التي يكون الغرض الوحيد منها هو تغليف المعلومات حول كائن واحد في مكان واحد. لن يكون لهذه الفئات أي سلوكيات (طرق) بخلاف أدوات الحصول/التعيين ووظيفة العرض (__str__). إذا كان هناك N كائنًا لإدارتها، يتم إنشاء مثيلات لهذه الفئات N مرة. ستكون [BaseEntity] هي الفئة الأم لهذا النوع من الفئات؛
- الفئات التي يتمثل دورها الأساسي في تغليف الطرق ومعلومات قليلة جدًا. سيتم إنشاء مثيلات لهذه الفئات مرة واحدة فقط (فئة فردية). ويتمثل دورها في تنفيذ خوارزميات التطبيق؛
فئة [BaseEntity] هي كما يلي:
تعليقات
- الغرض من فئة [BaseEntity] هو تسهيل عمليات التحويل بين الكائنات والقواميس وبين الكائنات وملفات JSON. وهي توفر الطرق التالية:
- [asdict]: تُرجع قاموسًا لخصائص الكائن؛
- [fromdict]: تنشئ كائنًا من قاموس؛
- [asjson]: تُرجع سلسلة JSON للكائن، على غرار الدالة [__str__]؛
- [fromjson]: تنشئ كائنًا من سلسلة JSON الخاصة به؛
- فئة [BaseEntity] مصممة لتكون مشتقة وليست للاستخدام كما هي؛
- الأسطر 22–25: تحتوي فئة [BaseEntity] على خاصية واحدة فقط، وهي العدد الصحيح [id]. هذه الخاصية هي معرف الكائن. في الممارسة العملية، غالبًا ما يكون من المفيد التمييز بين مثيلات الفئة نفسها. سنقوم بذلك باستخدام هذه الخاصية، التي تكون فريدة لكل مثيل. علاوة على ذلك، غالبًا ما تأتي الكائنات من قواعد البيانات حيث يتم تحديدها بواسطة مفتاح أساسي، وعادةً ما يكون عددًا صحيحًا. في مثل هذه الحالات، ستعمل [id] كمفتاح أساسي؛
- الأسطر 27–40: مُعيّن الخاصية [id]. نتحقق من أنها عدد صحيح >= 0. إذا لم يكن الأمر كذلك، يتم إلقاء استثناء من النوع [MyException] (السطر 39)؛
- السطر 10: [excluded_keys] هي سمة فئة، وليست سمة مثيل. لذلك، نكتب [BaseEntity.excluded_keys]. هذه السمة هي قائمة تحتوي على خصائص الفئة التي لا تشارك في تحويلات Object/Dictionary و Object/JSON؛
- الأسطر 12–16: [get_allowed_keys] تُرجع قائمة بخصائص الفئة. في تحويل Dictionary → Object أو JSON → Object، لن يتم قبول سوى المفاتيح الموجودة في هذه القائمة. ستحتاج كل فئة مشتقة من فئة [BaseEntity] إلى إعادة تعريف هذه القائمة؛
من المهم أن نفهم هنا أن خصائص ووظائف فئة [BaseEntity] متاحة للفئات المشتقة من [BaseEntity]. هذه هي النقطة الأساسية التي يجب فهمها.
سنقوم الآن بفحص كود فئة [BaseEntity] بالتفصيل. إنه متقدم جدًا. يمكن للقراء المبتدئين قراءة وصف دور كل دالة دون الخوض في الكود نفسه.
13.2.1. طريقة [BaseEntity.fromdict]
13.2.1.1. التعريف
تسمح لك طريقة [fromdict] بتهيئة كائن [BaseEntity] أو كائن مشتق من قاموس:
تعليقات
- السطر 1: تستقبل الدالة قاموس [state] كمعلمة، والذي سيتم من خلاله تهيئة الكائن الحالي؛
- السطر 4: نستدعي الدالة الثابتة [get_allowed_keys] للفئة التي استدعت الدالة [fromdict]. إذا كنا نتعامل مع فئة مشتقة من [BaseEntity] وقامت تلك الفئة المشتقة بإعادة تعريف الدالة الثابتة [get_allowed_keys] في [ ]، فإن الدالة [get_allowed_keys] هي التي يتم استدعاؤها. تعيد كل فئة مشتقة تعريف هذه الدالة الثابتة لإعلان خصائصها؛
- السطر 6: نقوم بالتكرار عبر مفاتيح وقيم قاموس [state]؛
- السطر 8: إذا لم يكن المفتاح [key] أحد خصائص الفئة، فإما:
- يتم تجاهله؛
- يتم إلقاء استثناء (السطر 10). يحدد المطور تفضيلاته عن طريق تمرير المعلمة [silent] المناسبة (السطر 1). تؤدي القيمة الافتراضية لـ [silent] إلى إلقاء استثناء في حالة محاولة تهيئة الكائن بخاصية لا يمتلكها؛
- السطر 14: إذا كان المفتاح من بين خصائص الكائن، يتم تعيينه إلى الكائن [self] باستخدام الدالة المحددة مسبقًا [setattr]؛
- السطر 16: تُرجع الدالة الكائن الذي تمت تهيئته؛
13.2.1.2. أمثلة

13.2.1.2.1. فئة [Utils]
فئة [Utils] (Utils.py) هي كما يلي:
يحدد، في الأسطر 3–11، طريقة ثابتة تُرجع قيمة منطقية true إذا كانت معلمتها [str] عبارة عن سلسلة غير فارغة؛
13.2.1.2.2. فئة [Person]
تشتق فئة [Person] (Person.py) من فئة [BaseEntity]:
- السطر 8: فئة [Person] مشتقة من فئة [BaseEntity]؛
- الأسطر 8–65: احتفظنا بمعظم فئة [Person] التي صادفناها سابقًا. الاختلافات هي كما يلي:
- لم تعد الفئة تحتوي على منشئ؛
- تستخدم الفئة استثناء [MyException]، على سبيل المثال، السطر 65؛
- تحتوي على طريقة ثابتة، [get_allowed_keys]، الأسطر 17–20، والتي تحدد قائمة خصائصها. تضاف الخصائص الخاصة بفئة [Person] إلى خصائص الفئة الأصلية [BaseEntity]؛
- تحتوي على قائمة ثابتة [excluded_keys]، والتي سنعود إليها لاحقًا؛
13.2.1.2.3. فئة [Teacher]
تشتق فئة [Teacher] (Teacher.py) من فئة [Person]:
- السطر 8: تمتد فئة [Teacher] (أو تنبثق من) فئة [Person]؛
- الأسطر 18–21: تحدد قائمة خصائص الفئة؛
- السطور 37–38: تعرض طريقة [show] هوية المعلم؛
13.2.1.2.4. تكوين [config]
تستخدم البرامج النصية النموذجية التكوين [config] التالي:
- الأسطر 8–10: الدلائل التي تحتوي على تبعيات المشروع؛
- الأسطر 14–15: يتم إنشاء مسار Python؛
- السطر 18: إرجاع قاموس فارغ (لا توجد تكوينات أخرى بخلاف syspath)؛
13.2.1.2.5. البرنامج النصي [fromdict_01]
النص البرمجي [fromdict_01] هو كما يلي:
- السطر 10: نقوم بإنشاء كائن [Teacher] من قاموس. للقيام بذلك، نستخدم المنشئ الافتراضي للفئة لإنشاء كائن [Teacher] نطبق عليه طريقة [fromdict]. من المهم أن نفهم أن طريقة [fromdict] التي يتم تنفيذها هنا هي طريقة الفئة الأم [BaseEntity]. في الواقع:
- يتم البحث أولاً عن طريقة [fromdict] في فئة [Teacher]. وهي غير موجودة؛
- ثم يتم البحث عنها في الفئة الأصلية [Person]. وهي غير موجودة؛
- ثم يتم البحث عنها في الفئة الأصلية [BaseEntity]. وهي موجودة؛
- السطر 11: يتم عرض الكائن [Teacher]؛
والنتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_01.py
Enseignant[1, paul, lourou, 56]
Process finished with exit code 0
13.2.1.2.6. البرنامج النصي [fromdict_02]
النص البرمجي [fromdict_02] هو كما يلي:
- السطر 10: نقوم بإنشاء معلم باسم أول فارغ. من المفترض أن يؤدي ذلك إلى ظهور استثناء لأن فئة [Person] لا تقبل أسماء أولى فارغة. يوضح هذا المثال الفرق بين القاموس والكائن. يمكن للكائن التحقق من صحة خصائصه، بينما لا يستطيع القاموس ذلك؛
والنتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_02.py
Traceback (most recent call last):
File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_02.py", line 10, in <module>
enseignant1 = Enseignant().fromdict({"id": 1, "nom": "lourou", "prénom": "", "âge": 56})
File "C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\classes\02/entities\BaseEntity.py", line 55, in fromdict
setattr(self, key, value)
File "C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\classes\02/entities\Personne.py", line 42, in prénom
raise MyException(11, "Le prénom doit être une chaîne de caractères non vide")
MyException.MyException: MyException[11, Le prénom doit être une chaîne de caractères non vide]
Process finished with exit code 1
13.2.1.2.7. البرنامج النصي [fromdict_03]
النص البرمجي [fromdict_03] هو كما يلي:
- السطر 10: نقوم بإنشاء معلم من قاموس يحتوي على مفتاح (الجنس) لا ينتمي إلى فئة [Teacher]. ومن المفترض أن يتم إثارة استثناء؛
والنتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_03.py
Traceback (most recent call last):
File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_03.py", line 10, in <module>
enseignant1 = Enseignant().fromdict({"id": 1, "nom": "lourou", "prénom": "albert", "âge": 56, "sexe": "M"})
File "C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\classes\02/entities\BaseEntity.py", line 51, in fromdict
raise MyException(2, f"la clé [{key}] n'est pas autorisée")
MyException.MyException: MyException[2, la clé [sexe] n'est pas autorisée]
Process finished with exit code 1
13.2.1.2.8. البرنامج النصي [fromdict_04]
البرنامج النصي [fromdict_04] هو نسخة من [fromdict_03] مع اختلاف بسيط واحد:
- السطر 10: استخدمنا المعلمة [silent=True] للإشارة إلى أنه إذا لم يكن مفتاح القاموس خاصية من خصائص فئة [Teacher]، فيجب تجاهله ببساطة. في هذه الحالة، لن يتم إثارة أي استثناء؛
والنتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromdict_04.py
Enseignant[1, albert, lourou, 56]
Process finished with exit code 0
13.2.2. طريقة [BaseEntity.asdict]
13.2.2.1. التعريف
تُرجع الطريقة [BaseEntity.asdict] قاموسًا تكون مفاتيحه هي خصائص الكائن:
def asdict(self, included_keys: list = None, excluded_keys: list =[]) -> dict:
# attributs de l'objet
attributes = self.__dict__
# les nouveaux attributs
new_attributes = {}
# on parcourt les attributs
for key, value in attributes.items():
# si la clé est explicitement demandée
if included_keys and key in included_keys:
self.set_value(key, value, new_attributes)
# sinon, si la clé n'est pas exclue
elif not included_keys and key not in self.__class__.excluded_keys and key not in excluded_keys:
self.set_value(key, value, new_attributes)
# on rend le dictionnaire des attributs
return new_attributes
تعليقات
- السطر 1: تُرجع الدالة [asdict] قاموس خصائص الكائن؛
- السطر 1: [included_keys]: قائمة المفاتيح المراد تضمينها في القاموس؛
- السطر 1: [excluded_keys]: قائمة المفاتيح التي سيتم استبعادها من القاموس؛
- السطر 3: تعيد الخاصية [self.__dict__] قاموس خصائص الكائن. أسماء الخصائص هي المفاتيح وقيمها هي قيم القاموس. قد يحتوي الكائن على مراجع إلى كائنات أخرى. في هذه الحالة، تُسبق أسماء الخصائص باسم الفئة التي تنتمي إليها. وهذا شيء لا نريده. نريد الخصائص بدون البادئة؛
- السطر 3: من المهم أن نفهم هنا أنه إذا تم تنفيذ الدالة [asdict] داخل فئة مشتقة من [BaseEntity]، فإن الخاصية [self.__dict__] تُرجع قاموس خصائص الكائن المشتق؛
- السطر 5: القاموس الذي سنقوم بإنشائه؛
- السطر 7: نكرر قيم [self.__dict__] في صيغة (المفتاح، القيمة)؛
- السطر 9: إذا كان المفتاح الحالي ينتمي إلى قائمة المفاتيح المراد تضمينها، فإنه يُضاف إلى قاموس [new_attributes] باستخدام الدالة [set_value]، التي سنصفها بعد قليل؛
- السطر 12: إذا لم يكن المعامل [included_keys] موجودًا، يتم استخدام المعامل [excluded_keys]. إذا لم تكن الخاصية من بين الخصائص المراد استبعادها، يتم إضافتها إلى قاموس [new_attributes]؛
- السطر 12: هناك عدة طرق لاستبعاد خاصية من القاموس:
- تم تعريفها على مستوى سمة الفئة [excluded_keys]؛
- تم تعريفها في قائمة [excluded_keys] التي تم تمريرها إلى دالة [asdict]؛
- وجود المعلمة [included_keys] وعدم تضمينها للخاصية؛
- السطر 15: نُرجع القاموس [new_attributes]
تكون دالة [set_value] الواردة في السطرين 10 و13 كما يلي:
تعليقات
- السطر 4: تحقق مما إذا كان المفتاح في صيغة __Class_key. هذه هي الصيغة التي يتخذها إذا كان ينتمي إلى كائن مضمن في الكائن الرئيسي. في هذه الحالة، نريد الاحتفاظ فقط بالسلسلة [key]؛
- السطر 7: نحتفظ فقط بالسلسلة التي تلي آخر حرفين تحت خط من السلسلة؛
- الأسطر 8-10: إذا لم يكن المفتاح في صيغة __Class_key، فإننا نحتفظ به كما هو؛
- الأسطر 11-14: يتم حساب القيمة المرتبطة بالمفتاح [newkey] بواسطة الطريقة الثابتة [BaseEntity.check_value]؛
الطريقة الثابتة [BaseEntity.check_value] هي كما يلي:
- السطر 1: طريقة [check_value] هي طريقة ثابتة (طريقة فئة، وليست طريقة مثيل). تأخذ كمعلمة القيمة المراد ربطها بمفتاح القاموس:
- السطر 17: إذا كانت هذه القيمة من النوع البسيط، فإنها تظل دون تغيير؛
- السطران 5-6: إذا كانت هذه القيمة من نوع BaseEntity، يتم استبدال القيمة بقاموسها. ينتج عن ذلك استدعاء متكرر؛
- السطران 8-9: إذا كانت هذه القيمة قائمة، يتم استبدالها بالقيمة [BaseEntity.list2list]؛
- السطران 11-12: إذا كانت هذه القيمة عبارة عن قاموس، يتم استبدالها بالقيمة [BaseEntity.dict2dict]؛
الطريقة الثابتة [BaseEntity.list2list] هي كما يلي:
- السطر 2: تستقبل الطريقة قائمة وتُرجع قائمة؛
- السطران 5-6: يتم استبدال كل قيمة في القائمة التي تم تمريرها كمعلمة بالقيمة التي تعيدها الطريقة الثابتة [BaseEntity.check_value]. وبالتالي، فإن هذا استدعاء متكرر. يتم استدعاء الطريقة الثابتة [BaseEntity.check_value] حتى تصبح معلمتها [value] من النوع البسيط (وليس من نوع BaseEntity أو قائمة أو قاموس)؛
الطريقة الثابتة [BaseEntity.dict2dict] هي كما يلي:
- السطر 2: تستقبل الطريقة قاموسًا وتُرجع قاموسًا؛
- السطران 5-6: يتم استبدال كل قيمة في القاموس الذي تم تمريره كمعلمة بالقيمة التي تعيدها الطريقة الثابتة [BaseEntity.check_value]. وبالتالي، فإن هذا استدعاء متكرر. يتم استدعاء الطريقة الثابتة [BaseEntity.check_value] حتى تصبح معلمتها [value] من النوع البسيط (وليس BaseEntity أو قائمة أو قاموس)؛
13.2.2.2. أمثلة
يوضح البرنامج النصي [asdict_01] الاستخدامات المختلفة للطريقة [asdict]:
نتائج التنفيذ هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/asdict_01.py
<class 'dict'>
{'_BaseEntity__id': 1, '_Personne__nom': 'lourou', '_Personne__prénom': 'paul', '_Personne__âge': 56}
{'id': 1, 'nom': 'lourou', 'prénom': 'paul', 'âge': 56}
{'id': 1, 'nom': 'lourou', 'prénom': 'paul'}
{"id": 1, "nom": "lourou", "âge": 56}
{'id': 2, 'nom': 'abélard', 'âge': 57}
{'nom': 'abélard'}
{'enseignants': [{'id': 1, 'nom': 'lourou', 'prénom': 'paul', 'âge': 56}, {'id': 2, 'nom': 'abélard', 'prénom': 'béatrice', 'âge': 57}]}
{'enseignants': [{'id': 1, 'nom': 'lourou', 'prénom': 'paul', 'âge': 56}, {'id': 2, 'nom': 'abélard', 'prénom': 'béatrice', 'âge': 57}], 'matières': {'maths': {'id': 1, 'nom': 'lourou', 'prénom': 'paul', 'âge': 56}, 'français': {'id': 2, 'nom': 'abélard', 'prénom': 'béatrice', 'âge': 57}}}
Process finished with exit code 0
- يوضح السطر 4 ميزة طريقة [asdict] مقارنة باستخدام الخاصية [__dict__]. يتم تجريد الخصائص من بادئة الفئة الخاصة بها. وهذا يجعل عرضها أسهل؛
- هناك عدة طرق لاستخدام طريقة [asdict]:
- إذا كنت تريد جميع الخصائص: استخدم طريقة [asdict] بدون معلمات؛
- إذا كنت تريد خصائص معينة فقط:
- إذا كان هناك عدد أكبر من الخصائص المطلوب تضمينها مقارنةً بالخصائص المطلوب استبعادها: استخدم المعلمة الفردية [excluded_keys]؛
- إذا كان عدد الخصائص المطلوب تضمينها أقل من عدد الخصائص المطلوب استبعادها: فسنستخدم المعلمة [included_keys] فقط؛
13.2.3. طريقة [BaseEntity.asjson]
تُرجع هذه الطريقة سلسلة JSON لكائن [BaseEntity] أو الفئات المشتقة منه. وتُخرج سلسلة JSON الخاصة بالقاموس الذي تُرجعه الطريقة [asdict]. وفيما يلي نص الكود:
- السطر 1: معلمات طريقة [asjson] هي معلمات طريقة [asdict]؛
فيما يلي مثال (asjson_01) يستخدم هذه الطريقة:
النتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/asjson_01.py
<class 'str'>
{"id": 1, "nom": "lourou", "prénom": "paul"}
{"id": 1, "nom": "lourou", "âge": 56}
{"id": 2, "nom": "abélard", "âge": 57}
{"nom": "abélard"}
{"enseignants": [{"id": 1, "nom": "lourou", "prénom": "paul", "âge": 56}, {"id": 2, "nom": "abélard", "prénom": "béatrice", "âge": 57}]}
{"enseignants": [{"id": 1, "nom": "lourou", "prénom": "paul", "âge": 56}, {"id": 2, "nom": "abélard", "prénom": "béatrice", "âge": 57}], "matières": {"maths": {"id": 1, "nom": "lourou", "prénom": "paul", "âge": 56}, "français": {"id": 2, "nom": "abélard", "prénom": "béatrice", "âge": 57}}}
Process finished with exit code 0
تستخدم طريقة [BaseEntity.__str__] طريقة [asjson] لعرض هوية كائن [BaseEntity] أو الكائنات المشتقة منه:
# toString
def __str__(self) -> str:
return self.asjson()
13.2.4. طريقة [BaseEntity.fromjson]
تسمح لك طريقة [BaseEntity.fromjson] بتهيئة كائن من نوع [BaseEntity] أو نوع مشتق من قاموس JSON. وفيما يلي شفرة هذه الطريقة:
- السطر 1: تأخذ هذه الطريقة معلمتين:
- [json_state]: قاموس JSON المستخدم لتهيئة كائن [BaseEntity]؛
- [silent]: للإشارة إلى ما إذا كان وجود مفتاح في قاموس JSON لا يمكن قبوله كخاصية لكائن [BaseEntity] يؤدي إلى حدوث استثناء (silent=False) أو يتم تجاهله ببساطة (silent=True)؛
- السطر 3: نبدأ بإنشاء قاموس Python الذي يمثل قاموس JSON، ثم نستخدم طريقة [fromdict] لتهيئة كائن [BaseEntity] من قاموس Python هذا؛
فيما يلي مثال (fromjson_01):
- السطر 11: نقوم بإنشاء سلسلة JSON لقاموس؛
- السطر 12: يتم تهيئة كائن [Enseignant] باستخدام هذه السلسلة؛
- السطر 13: يتم عرض المعلم؛
والنتائج هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/fromjson_01.py
Enseignant[1, paul, lourou, 56]
Process finished with exit code 0
13.2.5. البرنامج النصي [main]
يلخص البرنامج النصي [main] الطرق المختلفة التي تمت مناقشتها:
نتائج التنفيذ هي كما يلي:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/02/main.py
{'_ChildEntity__att1': 1, 'att2': 2}
{"att1": 1, "att2": 2}
MyException[2, la clé [att5] n'est pas autorisée]
{"att1": 1, "att2": 2, "att3": 3, "att4": 4}
{"att1": 1, "att2": 2, "att4": 4}
{'att2': 2, 'att4': 4}
{"att1": 1, "att4": 4}
MyException[1, L'attribut [att1] attend une valeur dans l'intervalle [1,10] (20)]
{"att1": 10, "att2": 20, "att4": {"att1": 1, "att2": 2, "att4": 4}}
{'att1': 1, 'att3': 3}
Process finished with exit code 0
لاحظ السطر 2 من النتائج: إنها الخاصية [ChildEntity.__dict__] (السطر 38 من الكود) التي تسمح لنا بتحديد أسماء الخصائص التي سيتم تضمينها في قوائم [included_keys] و [excluded_keys]. لاحظ، في السطر 2 من النتائج أيضًا، أنه اعتمادًا على ما إذا كانت الخاصية محددة داخل الفئة عبر getter/setter أو تم إنشاؤها كما يتم إنشاء مفتاح قاموس، فقد يتم أو لا يتم إرفاق اسم الفئة [ChildEntity] بها.