تُعرف لغة بايثون، باعتبارها لغة مفسرة عالية المستوى، بسهولة قراءتها ومبادئ تصميمها الرائعة. ومع ذلك، عندما تتعمق أكثر في بايثون، قد تبدو بعض الأشياء معقدة إذا كنت قادمًا من لغة لا تحتوي على ميزة مماثلة. إحدى هذه الميزات هي التوابع السحرية، وفي هذه المقالة، سنكشف غموض التوابع السحرية __str__ و__repr__، والاختلافات بينهما، ولماذا ومتى تستخدم كل منهما.
ما هي التوابع السحرية؟
التوابع السحرية في بايثون هي توابع خاصة تضيف “سحرًا” إلى فئاتك. وهي محاطة دائمًا بعلامتي سفلية مزدوجة (على سبيل المثال __init__ أو __lt__). تُعرف هذه التوابع أيضًا باسم أساليب dunder، وهي اختصار لـ “double under”. لا يُقصد من التوابع السحرية أن يتم استدعاؤها مباشرةً من قِبلك، ولكن الاستدعاء يحدث داخليًا من الفئة عند إجراء معين. على سبيل المثال، عند إضافة رقمين باستخدام عامل +
، داخليًا، سيتم استدعاء التابع __add__.
class Number:
def __init__(self, num):
self.num = num
def __add__(self, other):
return self.num + other.num
num1 = Number(2)
num2 = Number(3)
print(num1 + num2) # Output: 5
في المثال أعلاه، يمكنك أن ترى أن التابع __add__ تيستخدم لتمكين استخدام عامل +
. هذا هو سحر التوابع السحرية!
يمكن للتوابع السحرية أن تجعل فئاتك تتصرف بشكل أشبه بالأنواع المضمنة في بايثون، وتجعل الكود الخاص بك أكثر سهولة في الاستخدام.
فهم التابع __str__
يمثل التابع __str__ في بايثون التمثيل غير الرسمي أو القابل للطباعة بشكل جيد لكائن ما. يتم استدعاء هذه التابع بواسطة الدالة المضمنة str()
ودالة print
لتحويل الكائن إلى سلسلة.
دعونا نلقي نظرة على مثال حيث نقوم بتعريف فئة Person
باستخدام التابع __str__:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'Person(name={self.name}, age={self.age})'
p = Person('John Doe', 30)
print(p)
سيكون ناتج هذا الكود:
Person(name=John Doe, age=30)
في هذا المثال، يقوم التابع __str__ بإرجاع سلسلة تمثل كائن Person
في نموذج يمكن قراءته بواسطة الإنسان.
فهم التابع __repr__
من ناحية أخرى، يقوم التابع __repr__ بإرجاع سلسلة تصف تمثيلًا دقيقًا لا لبس فيه لكائن. والهدف الرئيسي من هذه التابع هو توضيح معلومات الكائن. وهي مخصصة للاستخدام في تصحيح الأخطاء والتطوير. يتم استدعاء طريقة __repr__ بواسطة الدالة المضمنة repr().
فيما يلي مثال حيث نقوم بتعريف فئة Person
باستخدام التابع __repr__ :
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Person(name={self.name!r}, age={self.age!r})'
p = Person('John Doe', 30)
print(repr(p))
سيكون ناتج هذا الكود:
Person(name='John Doe', age=30)
في هذا المثال، يقوم التابع __repr__ بإرجاع سلسلة إذا تم تقييمها، فإنها ستنتج كائنًا مكافئًا لـ p. لاحظ استخدام !r
في تنسيق السلسلة للتأكد من أن السلسلة الناتجة تستخدم repr()
بدلاً من str()
. هذا جزء من المحاولة لجعل الناتج لا لبس فيه.
ملاحظة: إذا لم تقم بتعريف التابع __str__ في فئتك، فسوف يقوم Python باستدعاء التابع __repr__ عند محاولة طباعة كائن.
الفرق بين __str__ و __repr__
في بايثون، تعد __str__
و__repr__
تابعين يخدمان غرضين مختلفين. للوهلة الأولى، قد تبدو التابعين متشابهين حيث تقوم كل منهما بإرجاع تمثيل نصي للكائن. ومع ذلك، فإن الاختلاف الرئيسي بينهما يكمن في الجمهور المستهدف ومستوى التفاصيل التي توفرها.
الغرض من التابع __str__
هو توفير وصف موجز يمكن قراءته من قبل البشر لكائن ما. وهو ما ستراه عند طباعة كائن ما. من ناحية أخرى، الغرض من التابع __repr__ هو توفير تمثيل كامل وواضح للكائن، وهو ما يكون أكثر فائدة للمطورين. وهو ما ستراه عند عرض الكائن في وحدة التحكم.
وهنا مثال لتوضيح هذا الاختلاف:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name} is {self.age} years old.'
def __repr__(self):
return f'Person({self.name}, {self.age})'
p = Person('John', 30)
print(p) # John is 30 years old.
p # Person(John, 30)
هنا، تستدعي print(p)
التابع __str__ وتعيد سلسلة نصية يمكن قراءتها بواسطة البشر. ومع ذلك، عندما تكتب p
في وحدة التحكم، تستدعي بايثون التابع __repr__
وتعيد سلسلة نصية أكثر تفصيلاً يمكن استخدامها لإعادة إنشاء الكائن.
لماذا ومتى نستخدم __str__
يستخدم التابع __str__
في المقام الأول لإنشاء تمثيل للكائن يمكن قراءته بواسطة الإنسان. إنها طريقة رائعة لتوفير ملخص أو وصف بسيط للكائن يمكن للمستخدمين النهائيين فهمه بسهولة.
قد ترغب في استخدام __str__
عند طباعة الكائنات لأغراض التسجيل أو التصحيح، أو عندما ترغب في عرض رسالة سهلة للمستخدم. على سبيل المثال، إذا كنت تقوم بتطوير لعبة، فقد تستخدم __str__
لطباعة إحصائيات اللاعب بتنسيق قابل للقراءة.
إليك كيفية استخدام __str__
في اللعبة:
class Player:
def __init__(self, name, level, health):
self.name = name
self.level = level
self.health = health
def __str__(self):
return f'Player {self.name} is at level {self.level} with {self.health} health points.'
player = Player('Hero', 10, 100)
print(player) # Player Hero is at level 10 with 100 health points.
في هذا المثال، يقوم التابع __str__
بإرجاع سلسلة توفر ملخصًا موجزًا للحالة الحالية للاعب. وهذا يجعل من السهل على المستخدمين فهم حالة اللاعب في لمحة.
لماذا ومتى تستخدم __repr__
التابع __repr__
في بايثون هو تابع خاص تعيد سلسلة يمثل نسخة قابلة للطباعة من كائن. ولكن متى نستخدمه؟ حسنًا، يهدف التابع __repr__
إلى أن يتكون واضح وكامل. وهذا يعني أنه إذا كان لديك كائن، فيجب أن يحتوي التابع __repr__
الخاص بهذا الكائن على جميع المعلومات اللازمة لإعادة إنشاء الكائن إذا تم إرجاعها إلى المترجم.
يجعل هذا الأمر __repr__
مفيدًا بشكل لا يصدق في تصحيح الأخطاء وتسجيلها، حيث يمكنه توفير نظرة عامة أكثر تفصيلاً لكائن ما مقارنةً بـ __str__
. إذا كنت تعمل مع هياكل بيانات معقدة، أو تحتاج إلى تمثيل كامل لكائنك لاستكشاف الأخطاء وإصلاحها، فإن __repr__
هو الحل.
ملاحظة: في حالة عدم وجود تابع
__str__
معرف، سيستخدم ايثون افتراضيًا__repr__
عند استدعاء دالةprint()
على كائن.
أمثلة: استخدام التابع __str__
الآن بعد أن ناقشنا التابع __repr__
، فلنغير الموضوع ونلقي نظرة على بعض الأمثلة حول كيفية استخدام التابع __str__
في بايثون. تذكر أن __str__
تهدف إلى إرجاع تمثيل نصي قابل للطباعة بشكل جيد لكائن، مما يجعلها رائعة لإخراج المستخدم النهائي.
دعنا نحدد فئة Person
بسيطة باستخدام طريقة __str__
:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'Person(name={self.name}, age={self.age})'
الآن، دعنا ننشئ مثيل Person
ونطبعه:
p = Person('John', 28)
print(p)
الناتج:
Person(name=John, age=28)
كما ترى، تستدعي دالة print()
طريقة __str__
وتطبع تمثيلًا نصيًا سهل الاستخدام لكائن بايثون. يمكن أن يكون هذا مفيدًا للغاية عندما تريد تقديم معلومات الكائن بتنسيق قابل للقراءة ونظيف.
أمثلة: استخدام طريقةالتابع __repr__
دعنا نتعمق في بعض الأمثلة لفهم استخدام repr في بايثون. لنفترض وجود فئة تسمى “Person” تحتوي على بعض السمات.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
إذا قمنا بإنشاء مثيل لهذه الفئة وحاولنا طباعتها، فسنحصل على رسالة غير مفيدة.
p = Person('John Doe', 30)
print(p)
الناتج:
<__main__.Person object at 0x7f3f8e7e3d30>
وهنا يأتي دور repr. فلنقم بإلغاء التابع repr في فئتنا.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Person(name={self.name}, age={self.age})'
الآن، عندما نقوم بإنشاء مثيل للفصل وطباعته، نحصل على مخرجات أكثر معنى.
p = Person('John Doe', 30)
print(p)
الناتج:
Person(name=John Doe, age=30)
يجب أن يعيد التابع __repr__
سلسلة نصية تمثل تعبيرًا صالحًا في بايثون. ومن المفترض أن تكون واضحة وكاملة. وهذا يعني أنه إذا قمت بنسخ ناتجها وتشغيلها، فيجب أن تحصل على نفس الكائن الذي تمت طباعته.
__str__
و__repr__
هما توابع خاصة في بايثون تسمحان لنا بالتحكم في كيفية تحويل الكائنات إلى سلاسل. في حين أن __str__
مخصصة لإنشاء تمثيل سلسلة قابل للقراءة للمستخدمين النهائيين، فإن __repr__
مصممة لإنشاء تمثيل سلسلة لا لبس فيه للمطورين. إن فهم الفرق بين هاتين التايعين ومتى تستخدم كل منهما أمر بالغ الأهمية لكتابة كود بايثون نظيف وفعال.
سواء كنت تقوم بتصحيح الأخطاء أو عرض البيانات، فإن هذه التوابع السحرية يمكن أن تجعل حياتك أسهل كثيرًا. تذكر أنه من الأفضل دائمًا تنفيذ __repr__
لفئاتك، وتنفيذ __str__
إذا كنت تعتقد أنه من المفيد الحصول على إصدار سلسلة من الكائن سهل الاستخدام.
اكتشاف المزيد من بايثون العربي
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.