Menu
العربية

الدوال في بايثون: def و return والوسائط الافتراضية

تعلّم كيف تُعرِّف الدوال في بايثون وتستخدمها: المعاملات، قيم الإرجاع، الوسائط الافتراضية، والوسائط المُسمّاة، مع عادات تسمية تُبقي الكود واضحًا ومقروءًا.

الدالة هي كتلة خطوات لها اسم

في كل مرة تجد نفسك تكرّر نفس السطور أكثر من مرة، أو تشعر برغبة في إعطاء اسم مختصر لمنطق صغير متكرر، فهذه إشارة واضحة أنك جاهز لكتابة دالة. الدوال في بايثون هي أول أداة حقيقية تساعدك على التعامل مع التعقيد وتنظيم الكود داخل برامجك.

الشكل الأساسي لتعريف دالة بايثون:

main.py
Output
Click Run to see the output here.

لنفكّك هذا السطر:

  • def هي الكلمة المفتاحية التي تبدأ بها تعريف الدالة.
  • greet هو اسم الدالة.
  • (name) هي قائمة المعاملات، أي المدخلات التي تستقبلها الدالة.
  • النقطتان الرأسيتان تُنهيان سطر الترويسة، وما يليهما من كتلة مُزاحة هو جسم الدالة.
  • greet("Ada") هذا استدعاء للدالة. هنا تُنفِّذ بايثون جسم الدالة بعد أن تربط name بالقيمة "Ada".

تبقى الدوال خامدة حتى تستدعيها. مجرد تعريف الدالة لا يُشغّلها، لكن استدعاءها بـ greet("Ada") هو ما يُشغّلها فعلاً.

المعاملات والوسائط في دوال بايثون

كلمة معامل (parameter) تشير إلى الاسم المكتوب داخل تعريف الدالة، أما الوسيط (argument) فهو القيمة التي تُمرِّرها عند الاستدعاء. الفرق قد يبدو شكلياً في الحديث العادي، لكنه مفيد جداً حين تقرأ رسائل الأخطاء وتحاول فهمها.

main.py
Output
Click Run to see the output here.

هنا base و exponent هما المعاملان (parameters)، بينما 2 و 10 هما الوسائط (arguments) التي نمررها. بايثون تربطها بالترتيب: الوسيط الأول يذهب إلى المعامل الأول، وهكذا.

return في بايثون: إرجاع قيمة إلى المُستدعي

الفرق بين print و return مهم: print يطبع على الشاشة فقط، أما return فيُعيد قيمة فعلية إلى الكود الذي استدعى الدالة حتى يستطيع استخدامها:

main.py
Output
Click Run to see the output here.

بدون return، تُرجع الدالة القيمة None افتراضيًا:

main.py
Output
Click Run to see the output here.

return يُنهي تنفيذ الدالة فورًا أيضًا. وكثيرًا ما تصادف استخدام الـ early return للخروج من الحالات الاستثنائية قبل الوصول إلى المنطق الأساسي:

main.py
Output
Click Run to see the output here.

الخروج المبكر عبر return يساعدك على تجنّب التداخل العميق للجسم الرئيسي داخل شروط if/else.

الوسائط الافتراضية في بايثون

يمكنك تحديد قيمة افتراضية لأي معامل، وتُستخدم هذه القيمة عندما لا يُمرِّر المستدعي قيمة صريحة:

main.py
Output
Click Run to see the output here.

جميع المعاملات التي لها قيم افتراضية يجب أن تأتي بعد المعاملات التي ليس لها قيم افتراضية. مثلًا def f(a, b=1, c): يعتبر خطأ في الصياغة (syntax error).

فخ القيمة الافتراضية المتغيّرة (mutable default)

هذه من أشهر المطبّات في بايثون. تابع معي المثال التالي:

main.py
Output
Click Run to see the output here.

كنت تتوقع أن كل استدعاء يبدأ بقائمة فارغة، لكن ما يحصل فعلياً هو أن القائمة الافتراضية مشتركة بين جميع الاستدعاءات، فتتراكم فيها العناصر. السبب أن بايثون يُقيّم القيمة الافتراضية مرة واحدة فقط عند تعريف الدالة، ثم يُعيد استخدام نفس القائمة إلى الأبد.

الحل الآمن هو استخدام None كقيمة افتراضية وإنشاء القائمة داخل الدالة نفسها:

main.py
Output
Click Run to see the output here.

الآن كل استدعاء لا يُمرّر items سيحصل على قائمة جديدة. هذه القاعدة تنطبق على القوائم والقواميس والمجموعات — أي شيء قابل للتعديل (mutable).

الوسائط المسماة في بايثون

تقدر تمرّر الوسائط بالاسم بدل الاعتماد على ترتيبها. هذا الأسلوب يسمح لك بتخطّي بعض المعاملات الوسطى، ويخلّي الاستدعاءات الطويلة أوضح وأسهل في القراءة:

main.py
Output
Click Run to see the output here.

يمكن الجمع بين الوسائط الموضعية والوسائط المسماة في استدعاء الدالة، لكن لا بد أن تأتي الوسائط الموضعية أولًا:

main.py
Output
Click Run to see the output here.

عندما يتجاوز عدد معاملات الدالة ثلاثة أو أربعة، فإن استخدام الوسائط المسماة يجعل استدعاء الدالة أوضح وأسهل في القراءة بكثير.

معاملات موضعية فقط ومعاملات مسماة فقط

تتيح لك بايثون تحديد بعض المعاملات بحيث تُمرَّر عن طريق الموضع فقط (باستخدام /) أو عن طريق الاسم فقط (باستخدام *):

main.py
Output
Click Run to see the output here.

لا تحتاجها من أول يوم. تصير مفيدة لما تبدأ بتصميم واجهات برمجية (APIs) وتريد تتحكم في الطريقة اللي يستدعي بها المستخدم دالتك.

docstring في بايثون وتسمية الدوال

أول سطر داخل أي دالة ممكن يكون docstring — نص محاط بثلاث علامات اقتباس تعامله بايثون كتوثيق للدالة:

main.py
Output
Click Run to see the output here.

أدوات مثل help() وتلميحات المحرر ومولّدات التوثيق تقرأ الـ docstring تلقائيًا، لذا حتى سطر واحد أفضل بكثير من لا شيء.

وخُذ وقتك في اختيار الأسماء:

  • أسماء الدوال يجب أن تكون أفعالًا: fetch_profile, compute_total, is_valid.
  • استخدم صيغة lower_snake_case.
  • الدوال التي تُرجع قيمة منطقية عادةً ما تبدأ بـ is_ أو has_ أو can_.

الاسم الجيد يجعل مكان الاستدعاء واضحًا بذاته دون الحاجة إلى تعليق يشرحه.

الدوال النقية (Pure Functions) أسهل في الفهم والتتبع

الدالة النقية (pure function) هي التي تُرجع نفس النتيجة لنفس المدخلات، ولا يكون لها أي آثار جانبية؛ فهي لا تُعدّل حالة عامة، ولا تطبع إلى stdout (إلا لأغراض التصحيح)، ولا تكتب إلى ملفات.

main.py
Output
Click Run to see the output here.

كلا الأسلوبين له مكانه، لكن في الكود الذي تنوي إعادة استخدامه واختباره، حاول قدر الإمكان أن تميل إلى الدوال النقية (pure functions).

مثال عملي صغير

إليك دالة بسيطة تجمع بين الوسائط الافتراضية والوسائط المسماة وreturn:

main.py
Output
Click Run to see the output here.

التالي: قوائم الوسائط المرنة

أحياناً ما تعرفش كم وسيط راح تستقبل الدالة، أو تبغى تمرّر الوسائط الواصلة كما هي لدالة ثانية. هنا يجي دور *args و **kwargs. نشوفهم بالتفصيل في الصفحة الجاية.

الأسئلة الشائعة

كيف أُعرِّف دالة في بايثون؟

تبدأ بالكلمة المفتاحية def متبوعةً باسم الدالة، ثم قوسين للمعاملات، ثم نقطتين رأسيتين. الكتلة المُزاحة تحت السطر هي جسم الدالة. مثال: def greet(name): print(f'Hi, {name}').

ما وظيفة return في بايثون؟

return تُرجِع قيمة إلى الجهة التي استدعت الدالة. وإذا لم تضع return صريحًا، فالدالة تُرجِع None تلقائيًا. بمجرد تنفيذ return تخرج الدالة فورًا، وأي كود يأتي بعده في الكتلة نفسها لن يُنفَّذ.

ما هي الوسائط الافتراضية في بايثون؟

الوسائط الافتراضية تسمح للمعامل بأن تكون له قيمة جاهزة تُستخدم إذا لم يُمرِّر المستدعي قيمة. مثلًا def greet(name='friend'): يعني أن استدعاء greet() بدون وسائط سيستخدم 'friend'. تجنّب تمامًا القيم الافتراضية القابلة للتعديل مثل []، وراجع النمط الآمن البديل أدناه.

تعلّم البرمجة مع Coddy

ابدأ الآن