الدوال في بايثون: كيف تكتب كودًا منظمًا قابلًا لإعادة الاستخدام
لماذا نحتاج الدوال، وكيف نعرّفها ونستدعيها، والمعاملات والقيم الافتراضية والقيم المرجعة، ونطاق المتغيرات، وكيف تقسّم مشكلة كبيرة إلى دوال صغيرة واضحة.
- 7 دقائق قراءة
تخيل أنك كتبت برنامجًا يحسب متوسط درجات طالب، ثم احتجت إلى الحساب نفسه لعشرين طالبًا في أماكن مختلفة من البرنامج. هل ستنسخ الأسطر نفسها عشرين مرة؟ وإذا اكتشفت خطأ صغيرًا في طريقة الحساب، هل ستصلحه في عشرين مكانًا؟ هنا يأتي دور الدوال (Functions): كتلة من الكود لها اسم، تكتبها مرة واحدة وتستدعيها كلما احتجت. الدوال من أهم المفاهيم في البرمجة كلها، لأنها تحول الكود من سطور متراكمة إلى أجزاء منظمة واضحة يمكن فهمها واختبارها وإعادة استخدامها. في هذا المقال نشرح الدوال في بايثون من البداية، بأمثلة تتدرج من البسيط إلى العملي.
ماذا ستتعلم في هذا المقال؟
- لماذا نحتاج إلى الدوال، وكيف نعرّفها ونستدعيها.
- المعاملات والقيم الافتراضية والمعاملات المسماة.
- الفرق بين الطباعة وإرجاع القيمة، ولماذا يهم.
- نطاق المتغيرات، وكيف تقسم مشكلة كبيرة إلى دوال صغيرة.
لماذا نحتاج إلى الدوال؟
هناك قاعدة مشهورة بين المبرمجين تسمى «لا تكرر نفسك» (Don’t Repeat Yourself). كل تكرار في الكود فرصة لخطأ جديد، وعبء إضافي عند التعديل. الدوال تحل هذه المشكلة، وتقدم ثلاث فوائد أخرى مهمة:
- الوضوح: اسم مثل
calculate_averageيشرح ما يحدث دون أن تقرأ التفاصيل. - الاختبار: تستطيع اختبار كل دالة وحدها والتأكد من صحتها قبل استخدامها في البرنامج الكبير.
- العمل الجماعي: يستطيع كل عضو في الفريق كتابة دوال مختلفة ثم تُجمع معًا.
في الحقيقة، أنت تستخدم الدوال منذ اليوم الأول: print() وlen() وinput() كلها دوال جاهزة كتبها مطورو بايثون. والآن حان الوقت لتكتب دوالك بنفسك.
تعريف الدالة واستدعاؤها
نعرّف الدالة بالكلمة def، ثم اسمها، ثم قوسين، ثم نقطتين رأسيتين. والأسطر التي تنتمي إلى الدالة تُكتب بمسافة بادئة:
def greet():
print("أهلًا بك في أكاديمية بدر التعليمية!")
greet()
greet()
كتابة def لا تنفذ شيئًا، بل «تعرّف» الدالة فقط. التنفيذ يحدث عندما «نستدعيها» بكتابة اسمها متبوعًا بالقوسين. في المثال السابق ستُطبع الرسالة مرتين.
المعاملات: أعط الدالة معلومات
الدالة السابقة تطبع الرسالة نفسها دائمًا. لنجعلها أذكى بإعطائها معاملًا (Parameter)، أي متغيرًا تستقبل فيه قيمة عند الاستدعاء:
def greet(name, course="بايثون"):
print(f"أهلًا {name}، مرحبًا بك في كورس {course}")
greet("مريم")
greet("يوسف", "الروبوتيكس")
greet(course="السيو", name="سارة")
في هذا المثال ثلاث أفكار مهمة. الأولى: المعامل name إلزامي. الثانية: المعامل course له قيمة افتراضية، فإذا لم نعطه قيمة استخدمت الدالة كلمة «بايثون». الثالثة: يمكننا تمرير القيم بأسمائها كما في الاستدعاء الأخير، وحينها لا يهم الترتيب، ويصبح الكود أوضح للقارئ.
إرجاع القيمة: الفرق الذي يربك المبتدئين
من أكثر النقاط إرباكًا الفرق بين أن تطبع الدالة نتيجة وأن ترجعها باستخدام return. الطباعة تعرض النتيجة على الشاشة فقط، ثم تضيع. أما الإرجاع فيسلّم النتيجة إلى من استدعى الدالة، ليحفظها في متغير أو يستخدمها في حساب آخر:
def average(scores):
if not scores:
return 0
return sum(scores) / len(scores)
math_avg = average([90, 80, 70])
science_avg = average([85, 95])
print("متوسط المادتين:", (math_avg + science_avg) / 2)
لاحظ أننا استخدمنا نتيجة الدالة في حساب جديد، وهذا مستحيل لو كانت الدالة تطبع فقط. ولاحظ أيضًا أننا تعاملنا مع حالة القائمة الفارغة، لأن القسمة على صفر تسبب خطأ. هذا التفكير في «الحالات الحدية» من علامات المبرمج الجيد. وعندما يصل التنفيذ إلى return تنتهي الدالة فورًا، وأي سطر بعدها داخل الدالة لن يُنفذ.
| المقارنة | print() | return |
|---|---|---|
| ماذا تفعل؟ | تعرض قيمة على الشاشة | تسلّم قيمة لمن استدعى الدالة |
| هل يمكن حفظ النتيجة في متغير؟ | لا، فالنتيجة تكون None | نعم |
| هل تنهي الدالة؟ | لا | نعم، فورًا |
| متى تستخدمها؟ | لعرض رسالة للمستخدم | عندما تحتاج النتيجة في خطوة لاحقة |
أشكال أخرى ستقابلها
دوال تستقبل عددًا غير محدد من القيم
أحيانًا لا تعرف مسبقًا كم قيمة ستصل إلى الدالة. في هذه الحالة تضع نجمة قبل اسم المعامل، مثل def total(*numbers)، فتستقبل الدالة كل القيم في صف واحد تستطيع المرور عليه بحلقة. وبالطريقة نفسها تستقبل النجمتان **options أي عدد من القيم المسماة في قاموس. ستراهما كثيرًا في مكتبات بايثون، ولا تحتاج إليهما في برامجك الأولى، لكن من المفيد أن تتعرف عليهما حين تقرؤهما.
الدوال المختصرة (lambda)
للعمليات القصيرة جدًا توجد دوال بلا اسم تُكتب في سطر واحد، مثل lambda x: x * 2. أشهر استخداماتها تحديد طريقة الترتيب، كترتيب قائمة الطلاب حسب درجاتهم. القاعدة: إذا احتاجت العملية إلى أكثر من تعبير بسيط، فاكتب دالة عادية باسم واضح.
نطاق المتغيرات
المتغير الذي تنشئه داخل دالة يعيش داخلها فقط، ويسمى متغيرًا محليًا. عندما تنتهي الدالة يختفي. أما المتغير الذي تنشئه خارج كل الدوال فيسمى متغيرًا عامًا، ويمكن قراءته من داخل الدوال. القاعدة العملية: اجعل الدالة تستقبل ما تحتاجه عبر المعاملات وتعيد نتيجتها عبر return، وتجنب الاعتماد على المتغيرات العامة أو تعديلها من داخل الدوال. هذا يجعل كل دالة مستقلة، يسهل فهمها واختبارها ونقلها إلى برنامج آخر.
كيف تقسم مشكلة كبيرة إلى دوال؟
المهارة الحقيقية ليست في كتابة دالة، بل في معرفة كيف تقسم برنامجًا إلى دوال مناسبة. لنأخذ مثالًا: برنامج يقرأ درجات الطلاب، ويحسب متوسط كل طالب، ويحدد تقديره، ويطبع تقريرًا.
def grade(avg):
if avg >= 90:
return "ممتاز"
elif avg >= 75:
return "جيد جدًا"
elif avg >= 50:
return "مقبول"
return "يحتاج إلى دعم"
students = {"مريم": [95, 88, 92], "يوسف": [70, 65, 80]}
for name, scores in students.items():
avg = average(scores)
print(f"{name}: {avg:.1f} – {grade(avg)}")
لاحظ أن كل دالة تؤدي مهمة واحدة واضحة، وأن اسمها يشرح هذه المهمة. إذا أردت لاحقًا تغيير حدود التقديرات، فستعدل دالة grade وحدها دون أن تلمس بقية البرنامج.
يشرح كوري شيفر في الفيديو التالي الدوال بأمثلة واضحة ومتدرجة، باللغة الإنجليزية:
كيف تتأكد أن دالتك تعمل؟
من أجمل مزايا الدوال أنك تستطيع اختبار كل منها وحدها. أبسط طريقة هي عبارة assert في بايثون: تكتب بعد الدالة سطرًا يقول إن نتيجة استدعاء معين يجب أن تساوي قيمة تعرفها مسبقًا، فإذا لم تتحقق المساواة يتوقف البرنامج برسالة خطأ واضحة. اختبر دالة المتوسط مثلًا بقائمة عادية، وبقائمة فيها عنصر واحد، وبقائمة فارغة. عندما تعدل الدالة لاحقًا، أعد تشغيل هذه الاختبارات لتتأكد أنك لم تكسر شيئًا كان يعمل. هذه العادة الصغيرة هي بداية ما يسميه المحترفون «الاختبارات الآلية»، وستجد لها أدوات متقدمة عندما تكبر مشروعاتك.
نصائح لكتابة دوال جيدة
- دالة واحدة، مهمة واحدة: إذا احتجت إلى كلمة «و» لوصف ما تفعله الدالة، ففكر في تقسيمها.
- أسماء بأفعال:
calculate_totalوsend_reportأوضح منtotalوreport. - دوال قصيرة: إذا تجاوزت الدالة شاشة واحدة، فغالبًا يمكن تقسيمها.
- وثّق الدالة: اكتب تحت سطر التعريف نصًا قصيرًا بين ثلاث علامات تنصيص يشرح ما تستقبله وما تعيده. يسمى هذا docstring، وتعرضه بايثون عند استخدام
help(). - اختبرها بحالات مختلفة: قيمة عادية، وقيمة حدية، وقيمة فارغة.
تمارين للتطبيق
- اكتب دالة تستقبل طول مستطيل وعرضه وتعيد مساحته، ثم دالة أخرى تعيد محيطه.
- اكتب دالة
is_evenتعيدTrueإذا كان العدد زوجيًا. - اكتب دالة تستقبل نصًا وتعيد عدد الكلمات فيه.
- اكتب دالة تحويل درجة الحرارة من مئوية إلى فهرنهايت، مع معامل اختياري يحدد اتجاه التحويل.
بعد الدوال، الخطوة التالية الطبيعية هي البرمجة كائنية التوجه التي تجمع البيانات والدوال في وحدة واحدة. وإذا أردت مراجعة الأساسيات، فارجع إلى مقال المتغيرات وأنواع البيانات. وفي كورس بايثون في أكاديمية بدر التعليمية نطبق الدوال في مشروعات حقيقية مع مراجعة الكود. ولمصادر إضافية زر المكتبة التعليمية، ولخطة كاملة جرّب أداة اكتشف مسارك.
الخلاصة
الدالة كتلة كود لها اسم، تستقبل معلومات عبر المعاملات، وتعيد نتيجة عبر return. استخدمها لتتجنب التكرار، ولتقسم البرنامج إلى مهام صغيرة واضحة يسهل اختبارها وتعديلها. تذكر: مهمة واحدة لكل دالة، واسم يصف ما تفعله.
© 2026 أكاديمية بدر التعليمية – هذا المحتوى حصري لأكاديمية بدر التعليمية. يُسمح بالاقتباس القصير مع ذكر المصدر ورابط الصفحة.
القسم: البرمجة
التعليقات (0)
يمكنك التعليق بدون حساب، ويظهر تعليقك بعد مراجعة الإدارة، وقد تُعدّل الصياغة قبل النشر.
لا توجد تعليقات بعد – كن أول من يشارك.


أضف تعليقًا