البرمجة كائنية التوجه في بايثون: التوابع السحرية Dunder Methods – بايثون

24

[ad_1]

لدى لغة بايثون Python أسماء توابع خاصة تبدأ وتنتهي بشرطتين سفليتين وتختصر بالسحرية، وتسمى عادةً التوابع السحرية أو التوابع الخاصة أو توابع داندر Dunder Methods، أنت تعرف مسبقًا اسم التابع السحري ‎__init__()‎ ولكن لدى بايثون العديد غيره، نستخدمهم عادةً لزيادة تحميل المعامل، أي إضافة سلوكيات خاصة تسمح لنا باستخدام كائنات الأصناف الخاصة بنا مع معاملات بايثون، مثل + أو >=. تسمح التوابع السحرية الأخرى لكائنات الأصناف الخاصة بنا بالعمل مع وظائف بايثون المضمنة مثل len()‎ و repe()‎.

كما هي الحال في ‎__init__()‎ أو توابع الجلب والضبط والحذف، لا نستدعي التوابع السحرية مباشرةً، يل تستدعيهم بايثون في الخلفية عندما تستخدم الكائنات مع المعاملات أو بعض الوظائف المضمنة. مثلًا، إذا أنشأت تابعًا اسمه ‎__len__()‎ أو ‎__repr__()‎ للأصناف الخاصة بك فستُستدعى في الخلفية عندما يمرر كائن من هذا الصنف إلى الدالة len()‎ أو repr()‎ على التوالي. هذه التوابع موثقة على الويب في توثيقات بايثون الرسمية.

سنحرص على التوسع في صنف WizCoin أثناء استكشافنا لأنواع التوابع السحرية المختلفة وذلك لتحقيق أكبر استفادة ممكنة.

توابع تمثيل السلاسل النصية السحرية

يمكن استخدام التوابع السحرية ‎__repr__()‎ و ‎__str__()‎ لإنشاء سلسلة نصية تمثل كائنات لا تتعامل معها بايثون عادةً، إذ تُنشئ بايثون عادةً سلاسل تمثيل نصية للكائنات بطريقتين، سلسلة repr النصية وهي سلسلة نصية لشيفرة بايثون التي تُنشئ نسخة من الكائن عندما تُنفذ، وسلسلة str النصية التي هي سلسلة يستطيع الإنسان قراءتها وتؤمن معلومات واضحة ومفيدة عن الكائن. تعاد سلاسل repr و str عن طريق الدوال المبنية مسبقًا repr()‎ و str()‎ على التوالي. مثلًا، أدخل التالي إلى الصدفة التفاعلية لرؤية السلسلتين النصيتين repr و str للكائن datetime.date:

>>> import datetime
1 >>> newyears = datetime.date(2021, 1, 1)
>>> repr(newyears)
2 'datetime.date(2021, 1, 1)'
>>> str(newyears)
3 '2021-01-01'
4 >>> newyears
datetime.date(2021, 1, 1)

في هذا المثال، سلسلة repr‏ -أي datetime.date(2021, 1, 1)‎– للكائن datetime.date(السطر 2) هي حرفيًا سلسلة نصية لشيفرة بايثون التي تُنشئ نسخةً من الكائن (السطر 1). تؤمن هذه النسخة تمثيلًا دقيقًا للكائن، ومن جهة أخرى، السلسلة النصية str‏ -أي 2021-01-01– للكائن datetime.date (السطر 3) هي سلسلة نصية تمثل قيمة الكائن بطريقة سهلة القراءة للبشر. إذا أدخلنا ببساطة الكائن في الصدفة التفاعلية (السطر 4)، تظهِر السلسلة النصية repr. تظهر غالبًا السلسلة النصية str للمستخدمين وتُستخدم السلسلة النصية repr للكائن في السياق التقني مثل رسائل الخطأ والسجلات.

تعلم بايثون كيفية إظهار الكائنات في أنواعها المبنية مسبقًا مثل الأعداد الصحيحة والسلاسل النصية، ولكنها لا تعلم كيفية إظهار الكائنات للأصناف التي أنشأناها نحن. إذا لم يعرف repr()‎ كيفية إنشاء سلسلة نصية repr أو str لكائن، ستكون السلسلة النصية مغلفة بأقواس مثلثة وتحتوي عنوان الذاكرة واسم للكائن '<wizcoin.WizCoin object at 0x00000212B4148EE0>' لإنشاء هذا النوع من السلاسل النصية لكائن WizCoin أدخل التالي إلى الصدفة التفاعلية:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)
>>> str(purse) 
'<wizcoin.WizCoin object at 0x00000212B4148EE0>'
>>> repr(purse) 
'<wizcoin.WizCoin object at 0x00000212B4148EE0>'
>>> purse
<wizcoin.WizCoin object at 0x00000212B4148EE0>

لا تمتلك هذه السلاسل فائدة كبيرة وصعبة القراءة، لذا يمكننا إخبار بايثون ما نريد استخدامه عن طريق تطبيق التوابع السحرية ‎__repr__()‎ و ‎__str__()‎؛ إذ يحدد التابع ‎__repr__()‎ أي سلسلة نصية يجب أن تُعيدها بايثون عندما يمرر الكائن إلى الدالة المبنية مسبقًا repr()‎؛ بينما يحدد التابع ‎__str__()‎ أي سلسلة نصية يجب أن تُعيدها بايثون عندما يمرر الكائن إلى الدالة المبنية مسبقًا str()‎. ضِف التالي إلى نهاية ملف wizcoin.py:

--snip--
    def __repr__(self):
        """Returns a string of an expression that re-creates this object."""
        return f'{self.__class__.__qualname__}({self.galleons}, {self.sickles}, {self.knuts})'

    def __str__(self):
        """Returns a human-readable string representation of this object."""
        return f'{self.galleons}g, {self.sickles}s, {self.knuts}k'

عندما نمرر purse إلى repr()‎ و str()‎ يستدعي بايثون التوابع السحرية ‎__repr__()‎ و ‎__str__()‎، أي نحن لا نستدعي التوابع السحرية في الشيفرة الخاصة بنا.

لاحظ أن السلسة النصية f التي تضم الكائن في الأقواس تستدعي ضمنًا str()‎ للحصول على السلسة النصية str. مثلًا أدخل التالي إلى الصدفة التفاعلية:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)
>>> repr(purse)  # Calls WizCoin's __repr__() behind the scenes.
'WizCoin(2, 5, 10)'
>>> str(purse)  # Calls WizCoin's __str__() behind the scenes.
'2g, 5s, 10k'
>>> print(f'My purse contains {purse}.')  # Calls WizCoin's __str__().
My purse contains 2g, 5s, 10k.

عندما نمرر الكائن WizCoin في purse إلى الدالتين repr()‎ و str()‎، تستدعي بايثون في الخلفية التابعين ‎__repr__()‎ و ‎__str__()‎ الخاصين بالصنف WizCoin. برمجنا هذين التابعين ليعيدا سلاسلًا نصيةً مفيدةً وسهلة القراءة. إذا أدخلت نص السلسلة النصية repr‏ التالية ‎'WizCoin(2, 5, 10)'‎ إلى الصدفة التفاعلية ستُنشئ كائن WizCoin لديه نفس سمات الكائن في purse. السلسلة النصية str هي تمثيل أسهل للقراءة لقيمة الكائن 2g, 5s, 10k. إذا استخدمت الكائن WizCoin في السلسلة النصية f، ستستخدم بايثون السلسلة النصية str الخاصة بالكائن.

إذا كانت الكائنات WizCoin معقدة لدرجة أنه من المستحيل إنشاء نسخة منها باستدعاء دالة بانية Constructor Function واحدة، نغلف السلسلة النصية repr في قوسين مثلثين للتنويه على أنه لا يمكن أن تصبح شيفرة بايثون. هكذا تكون سلسلة تمثيل نصي العامة، مثل '<wizcoin.WizCoin object at 0x00000212B4148EE0>'. كتابة ذلك في الصَدَفة التفاعلية سيرفع خطأ SyntaxError حتى لا يحدث ارتباك بشيفرة بايثون التي تُنشئ نسخة من ذلك الكائن.

نستخدم __self.__class__.__qualname بدلًا من توفير السلسلة النصية WizCoin في الشيفرة داخل التابع ‎__repr__()‎، إذ يستخدم التابع الموروث ‎__repr__()‎ اسم الصنف الفرعي بدلًا من WizCoin. إذا أعدنا تسمية الصنف WizCoin سيستخدم التابع ‎__repr__()‎ الاسم الجديد تلقائيًا. تظهِر السلسلة النصية str للكائن WizCoin السمة بصورة أنيقة ومختصرة. يُفضّل جدًا تطبيق ‎__repr__()‎ و ‎__str__()‎ في كل الأصناف الخاصة بك.

المعلومات الحساسة في سلاسل REPR النصية

كما ذكرنا سابقًا، نظهر السلاسل النصية str للمستخدمين ونستعمل السلاسل النصية repr في سياق تقني مثل السجلات. ولكن يمكن أن تسبب السلاسل النصية repr مشاكل أمنية، إذا كان الكائن المُنشئ يحتوي على معلومات حساسة مثل كلمات المرور والتفاصيل الطبية والمعلومات الشخصية؛ ففي هذه الحالة تأكد من خلو التابع ‎__repr__()‎ من هذه المعلومات في السلسلة النصية المرجعة، وعند تعطل البرنامج، يجري إعداده بصورة متكررة لتضمين محتويات المتغيرات في ملف السجل للمساعدة في تصحيح الأخطاء، ولا تُعامل عادةً ملفات الدخول هذه على أنها معلومات حساسة. تحتوي ملفات الدخول المفتوحة للعلن في العديد من الحوادث الأمنية كلمات المرور وأرقام بطاقات بنكية وعناوين المنازل ومعلومات حساسة أخرى، خذ ذلك بالحسبان عند كتابة التوابع ‎__repr__()‎ الخاص بصنفك.

التوابع السحرية العددية Numeric Dunder Methods

تزيد التوابع السحرية العددية أو التوابع السحرية الرياضية من تحميل عامل بايثون الرياضية، مثل + و - و * و / وما شابه. لا نستطيع حاليًا تنفيذ عملية رياضية مثل جمع كائني WizCoin باستخدام العامل +، وإذا حاولنا فعل ذلك سترفع بايثون استثناء TypeError لأنها لا تعرف كيفية إضافة كائنات WizCoin. أدخل التالي إلى الصدفة التفاعلية لمشاهدة هذا الخطأ:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)
>>> tipJar = wizcoin.WizCoin(0, 0, 37)
>>> purse + tipJar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'WizCoin' and 'WizCoin'

يمكنك استخدام التابع السحري ‏()‏‏__add__‏ بدلًا من كتابة التابع ‎addWizCoin()‎‎‏‏‏‎ لصنف WizCoin، لكي تعمل كائنات WizCoin مع العامل +. أضف التالي إلى نهاية ملف wizcoin.py:

--snip--
1     def __add__(self, other):
        """Adds the coin amounts in two WizCoin objects together."""
2         if not isinstance(other, WizCoin):
            return NotImplemented

3         return WizCoin(other.galleons + self.galleons, other.sickles + self.sickles, other.knuts + self.knuts)

تستدعي بايثون التابع ()__add__عندما يكون الكائن WizCoin على يسار المعامل + وتمرر القيمة على الجانب الأيمن من المعامل + للمعامل other (يمكن تسمية المعامل أي شيء ولكن الاصطلاح هو other).

تذكر أنه يمكن تمرير أي نوع من أنواع الكائنات إلى التابع ()__add__، لذا يجب على التابع أن يحتوي اختبارات من النوع، فمثلًا ليس من المنطقي إضافة رقم عشري أو عدد صحيح إلى كائن WizCoin لأننا لا نعرف إذا كان يجب إضافته إلى galleons أو sickles أو knuts.

يُنشئ التابع ()__add__ كائن WizCoin جديد مع كميات تساوي مجموع السمات galleons و sickles و knuts من self و other3 لأن هذه السمات الثلاث تحتوي الأعداد الصحيحة التي يمكننا استخدام المعامل + عليهم. الآن بعد أن حمّلنا العامل + لصنف WizCoin، يمكننا استخدام العامل + على الكائن WizCoin.

يسمح لنا زيادة تحميل العامل + بكتابة شيفرة أكثر قابليّة للقراءة. مثلًا، أدخل التالي إلى الصدفة التفاعلية:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)  # إنشاء كائن‫ WizCoin
>>> tipJar = wizcoin.WizCoin(0, 0, 37)  # إنشاء كائن‫ WizCoin آخر
>>> purse + tipJar  # إنشاء كائن‫ WizCoin آخر يحتوي على المجموع
WizCoin(2, 5, 47)

إذا مُرر نوع الكائن الخطأ إلى other، لن يرفع التابع السحري استثناءً ولكنه سيعيد القيمة المبنية مسبقًا NotImplemented، فمثلًا، other في الشيفرة التالية هي عدد صحيح:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)
>>> purse + 42  # لا يمكن إضافة كائنات‫ WizCoin مع الأعداد الصحيحة
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'WizCoin' and 'int'

تشير إعادة NotImplemented إلى بايثون لاستدعاء التوابع لتؤدي هذه العملية. سنتوسع حول “التوابع السحرية العددية المعكوسة” بتفصيل أكثر في هذا المقال. تستدعي بايثون في الخلفية التابع ()__add__ مع 42 للمعامل other الذي يعيد NotImplemented مما يؤدي لأن ترفع بايثون TypeError.

على الرغم من أنه لا يجب إضافة الأعداد الصحيحة أو طرحهم من الكائن WizCoin إلا أنه من المنطقي السماح للشيفرة بضرب كائنات WizCoin بأعداد صحيحة موجبة عن طريق تعريف تابع سحري ()__mul__. ضِف التالي في نهاية الملف wizcoin.py:

--snip--
    def __mul__(self, other):
        """Multiplies the coin amounts by a non-negative integer."""
        if not isinstance(other, int):
            return NotImplemented
        if other < 0:
            # Multiplying by a negative int results in negative
            # amounts of coins, which is invalid.
            raise WizCoinException('cannot multiply with negative integers')

        return WizCoin(self.galleons * other, self.sickles * other, self.knuts * other)

يسمح لك التابع ()__mul__ بضرب كائنات WizCoin بأعداد صحيحة موجبة. إذا كان other عدد صحيح، فهذا يعني أنه نوع البيانات التي يتوقعه التابع ()__mul__ ولا يجب أن نعيد NotImplemented. ولكن إذا كان العدد الصحيح سالبًا، هذا يعني أن ضربه الكائن WizCoin سيعطي قيم سلبية للنقود في الكائن WizCoin لأن هذا يتعارض مع تصميمنا للصنف، نرفع WizCoinException مع رسالة خطأ مفصلة.

ملاحظة: لا يجب تغيير الكائن self في التابع السحري العددي، بل يجب على التابع إنشاء وإعادة كائن جديد بدلًا من ذلك، إذ يُتوقع من العامل + ومن باقي العوامل أيضًا تقييم كائن جديد بدلًا من تعديل قيمة الكائن الموضعي.

أدخل التالي في الصدفة التفاعلية لمشاهدة عمل التابع السحري ()__mul__:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)  # إنشاء كائن‫ WizCoin
>>> purse * 10  # ‫اضرب كائن WizCoin بعدد صحيح
WizCoin(20, 50, 100)
>>> purse * -2  # الضرب بعدد صحيح سالب يتسبب بخطأ
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Al\Desktop\wizcoin.py", line 86, in __mul__
    raise WizCoinException('cannot multiply with negative integers')
wizcoin.WizCoinException: cannot multiply with negative integers

يظهر الجدول 1 قائمة التوابع السحرية العددية، لا توجد حاجة لتنفيذ كل التوابع في الصنف الخاص بك. حدد التوابع التي تفيدك.

التابع السحري العملية المعامل أو الدالة المضمنة
()__add__ جمع +
()__sub__ طرح -
()__mul__ ضرب *
()__matmul__ ضرب المصفوفات (جديد في بايثون 3.5) @
()__truediv__ قسمة /
()__floordiv__ قسمة عدد صحيح //
()__mod__ نسبة %
()__divmod__ قسمة ونسبة divmode()‎
()__pow__ رفع للأس **, pow
()__lshift__ انتقال لليسار >>
()__rshift__ انتقال لليمين <<
()__and__ عملية ثنائية و &
()__or__ عملية ثنائية أو |
()__xor__ عملية ثنائية أو حصرية ^
()__neg__ سلبي أحادي - كما في -42
()__pos__ هوية أحادي + كما في +42
()__abs__ قيمة مطلقة ()abs
()__invert__ عملية ثنائية عكس ~
()__complex__ شكل العدد العقدي complex()‎
()__int__ شكل العدد الصحيح int()‎
()__float__ شكل العدد العشري float()‎
()__bool__ شكل بولياني bool()‎
()__round__ التدوير round()‎
()__trunc__ الاختصار math.trunc()‎
()__floor__ التدوير للأسفل math.floor()‎
()__ceil__ التدوير للأعلى math.ceil()‎

الجدول 1: التوابع السحرية العددية

بعض هذه التوابع مهمة لصنف WizCoin، حاول كتابة التطبيق الخاص بك لكل من التوابع ()__sub__ و ()__pow__ و ()__int__ و ()__float__ و ()__bool__. يمكنك مشاهدة أمثلة عن التطبيقات من خلال الرابط https://autbor.com/wizcoinfull. التوثيق الكامل للتوابع السحرية العددية موجود في توثيقات بايثون على الرابط https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types.

تسمح التوابع السحرية العددية للكائنات الخاصة بأصنافك استخدام العوامل الرياضية الخاصة ببايثون. استخدم التوابع السحرية العددية في حال كتبت توابع تصف مهمة تابع موجود سابقًا أو دالة مبنية مسبقًا، مثل التابعين multiplyBy()‎ أو convertToInt()‎ أو ما شابه، إضافةً إلى التوابع السحرية المعكوسة أو الموضعية المشروحة في الفقرتين التاليتين.

التوابع السحرية العددية المعكوسة

تستدعي بايثون التوابع السحرية العددية عندما يكون الكائن على يسار العامل الرياضي، ولكنها تستدعي التابع السحري العددي المعكوس (يسمى أيضًا التابع السحري العددي العكوس أو اليد اليمين) عندما يكون الكائن على الطرف اليمين من العامل الرياضي.

التوابع السحرية العددية المعكوسة مفيدة لأن المبرمجين الذين يستخدمون الأصناف الخاصة بك لا يكتبون دومًا الكائن على الطرف اليسار من العامل الذي يقود بدوره لسلوك غير متوقع. لنرى مثلًا ما سيحدث عندما تحتوي purse كائن WizCoin وتعطي بايثون القيمة للتعبير 2 * purse حيث purse هي على الطرف اليمين للمعامل.

  1. يُستدعى التابع ()__mul__ للصنف int لأن 2 هو عدد صحيح، وذلك مع تمرير purse للمعامل other.
  2. لا يعرف التابع ()__mul__ للصنف int كيف يتعامل مع الكائنات WizCoin لذا يُعيد NotImplemented.
  3. لا ترفع بايثون الخطأ TypeError الآن لأن purse تحتوي كائن WizCoin، ويُستدعى التابع ()__rmul__ الخاص بالصنف WizCoin باستخدام 2 ويُمرر إلى المعامل other.
  4. ترفع بايثون الخطأ TypeError إذا أعاد التابع ‎__‎rmul__‎()‎‏ القيمة NotImplemented.

ما عدا ذلك تكون القيمة المعادة من ()__rmul__ هي نتيجة التعبير 2 * purse.

يعمل التعبيرpurse * 2 بصورة مختلفة عندما تكون purse على الجانب الأيسر من المعامل:

  1. لأن purse تحتوي كائن WizCoin، إذ يُستدعى تابع ()__mul__ الخاص بالصنف WizCoin ويمرر 2 للمعامل other.
  2. ينشئ التابع ()__mul__ كائن WizCoin جديد ويعيده.
  3. الكائن المُعاد هو قيمة التعبير purse * 2.

لدى التوابع السحرية العددية والتوابع السحرية العددية المعكوسة نفس الشيفرة إذا كانت متبادلة. العوامل المتبادلة مثل الجمع لديها نفس النتيجة بالاتجاهين، 3+2 هي نفس 2+3، ولكن المعاملات الأخرى ليست تبادلية فمثلًا 3-2 ليست 2-3. أي عملية تبادلية يمكنها استدعاء نفس التابع السحري العددي الأساسي عندما يُستدعى التابع السحري العددي المعكوس؛ فمثلًا، أضف التالي في نهاية ملف wizcoin.py لتعريف التابع السحري العددي المعكوس لعامل الضرب:

--snip--
    def __rmul__(self, other):
        """Multiplies the coin amounts by a non-negative integer."""
        return self.__mul__(other)

ضرب عدد صحيح بكائن WizCoin هو تبادلي، إذ أن 2 * purse هي نفس purse * 2. بدلًا من نسخ ولصق الشيفرة من ()__mul__ نستدعي فقط self.__mul__()‎ ونمررها للمعامل other.

بعد تحديث mizcoin.py، جرب استخدام تابع الضرب السحري المعكوس عن طريق إدخال التالي إلى الصدفة التفاعلية:

>>> import wizcoin
>>> purse = wizcoin.WizCoin(2, 5, 10)
>>> purse * 10  # ‪‫يستدعي ‎__mul__()‎ بقيمة 10 للمعامل other
WizCoin(20, 50, 100)
>>> 10 * purse  #  ‪‫يستدعي ‎__rmul__()‎ بقيمة 10 للمعامل other
WizCoin(20, 50, 100)

تذكر أن بايثون تستدعي في التعبير 10 * purse تابع ‏‏()__mul__‏‏ الخاص بالصنف int لمعرفة ما إذا كان بإمكان العدد الصحيح أن يُضرب بكائنات WizCoin. لا يعلم طبعًا صنف بايثون int المبني مسبقًا أي شيء عن الأصناف التي أنشأناها، لذا تعيد NotImplemented. هذا يشير لبايثون باستدعاء التابع ()__rmul__ الخاص بصنف WizCoin، وإذا كان موجودًا للتعامل مع العملية الحسابية،ترفع بايثون استثناء TypeError إذا كان الاستدعائين للتابعين ()__mul__ و ()__rmul__ للصنفين Int و WizCoin على التتالي يعيدان NotImplemented.

يمكن إضافة كائنات WizCoin إلى بعضها فقط، وهذا يضمن أن التابع الأول ()__add__ الخاص بالصنف WizCoin سيتعامل مع المعامل لذا لا نحتاج لتنفيذ ()__radd__. مثلًا، في التعبير purse + tipJar يُستدعى التابع ()__add__ للكائن purse وتمرّر tipJar للمعامل other. لا تحاول بايثون استدعاء تابع ()__radd__ الخاص بالكائن tipJar لأن هذا الاستدعاء لن يعيد NotImplemented، وتكون purse هي المعامل other.

يحتوي الجدول 2 على قائمة كاملة للتوابع السحرية العددية المعكوسة.

التابع السحري العملية المعامل أو الدالة المضمنة
()__radd__ جمع +
()__rsub__ طرح -
()__rmul__ ضرب *
()__rmatmul__ ضرب المصفوفات (جديد في بايثون 3.5) @
()__rtruediv__ قسمة /
()__rfloordiv__ قسمة عدد صحيح //
()__rmod__ نسبة %
()__rdivmod__ قسمة ونسبة divmode()‎
()__rpow__ رفع للأس pow, **
()__rlshift__ انتقال لليسار <<
()__rrshift__ انتقال لليمين >>
()__rand__ عملية ثنائية و &
()__ror__ عملية ثنائية أو |
()__rxor__ عملية ثنائية أو حصرية ^

الجدول 2: التوابع السحرية العددية المعكوسة

التوثيق الكامل للتوابع السحرية المعكوسة موجود في توثيقات بايثون.

الخلاصة

تسمح لك بايثون بإعادة تعريف العوامل باستخدام التوابع السحرية التي تبدأ وتنتهي بمحرفي شرطة سفلية، كما يمكن إعادة صياغة العوامل الرياضية الشائعة باستخدام التوابع السحرية العددية والمعكوسة، إذ تقدم هذه التوابع طريقة لعمل عوامل بايثون الموضعية مع كائنات الأصناف التي أنشأتها وإذا لم تكن قادرة على التعامل مع نوع بيانات الكائن على الطرف الأخر من المعامل ستعيد قيمة NotImplemented المبنية مسبقًا. تُنشئ هذه التوابع السحرية وتعيد كائنات جديدة، في حين تُعدل التوابع السحرية الموضعية (التي تُعيد تعريف معاملات الإسناد المدعومة) الكائنات موضعيًا. لا تنفذ التوابع السحرية المقارنة معاملات بايثون الستة للمقارنة فقط، ولكن تسمح لدالة بايثون sort()‎ بترتيب كائنات الأصناف الخاصة بك. ستحتاج لاستخدام الدوال eq()‎ و ne()‎ و lt()‎ و le()‎ و gt()‎ و ge()‎ في وحدة العامل لمساعدتك في تنفيذ هذه التوابع السحرية.

تسمح الخواص والتوابع السحرية بكتابة الأصناف الخاصة بك بطريقة متناسقة وقابلة للقراءة، كما تسمح لك بتفادي الشيفرة النمطية التي تتطلبها لغات البرمجة الأخرى مثل جافا. لتعلم كتابة شيفرة بايثون هناك حديثان لريموند هيتغير Raymond Hettiger يتوسعان في هذه الأفكار “تحويل الشيفرة إلى بايثون اصطلاحية“. و”ما وراء PEP 8 – أفضل الممارسات لشيفرة جميلة وواضحة” التي تغطي بعض المفاهيم التي ذكرناها وأكثر.

ترجمة -وبتصرف- لقسم من الفصل Pythonic OOP: Properities and dunder methods من كتاب Beyond the Basic Stuff with Python.

اقرأ المزيد

[ad_2]

المصدر