Path: blob/master/الفصل السادس-كتابة الدوال.ipynb
675 views
الفصل السادس : كتابة الدوال
أهداف الفصل
عند إتمام هذا الفصل يجب أن يكون لديك إلمام بالآتي:
- كيفية كتابة دالة وطريقة استدعائها.
- التعرف على أنواع مدخلات الدوال وكيفية استخدامها.
- التعرف على الدوال الداخلية وخواصها
- التعرف على مخرجات الدوال.
- تعلم الطريقة المختصرة لكتابة الدوال عن طريق استخدام lambda
- التعرف على الطريقة الصحيحة لكتابة تعليقات إرشادية تشرح كيفية استخدام الدوال.
تعريف الدوال
استدعاء الدوال
لا يتم تنفيذ الكود داخل الدالة إلاّ بعد استدعائها وذلك بكتابة اسم الدالة متبوعا بقوسين بداخلهما مدخلات الدالة إن كان هناك مدخلات للدالة أما إذا لم يكن هناك مدخلات للدالة فيكتفى بكتابة قوسين فارغين كما في المثال التالي
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_28909/2987341299.py in <module>
----> 1 myinfo()
NameError: name 'myinfo' is not defined
لذلك يمكن كتابة تعريف الدالة في أي مكان من البرنامج شريطة أن لا يسبق استدعاءها تعريفها عند كتابة البرنامج. لاحظ أيضاً أن في الأمثلة السابقة كتبنا قوسي الدالة فارغين لأن الدالة لاتتطلب أي معلومات إضافية لتنفيذ الكود البرمجي داخلها.
مدخلات الدوال
لنفرض الآن أننا نريد كتابة دالة أكثر ذكاءً بحيث تقوم بالقاء التحية على أي شخص ندخل اسمه للدالة. للقيام بهذه المهمة يمكن كتابة الدالة بالطريقة التالية
أنواع مدخلات الدوال
تفيد رسالة الخطأ السابقة أنه تم تعريف الدالة power بمتغير الزامي a لكن هذا المتغير كان مفقوداً عند استدعاء الدالة. وعندما نزودها بهذه القيمة فإن الدالة تفنذ بشكل طبيعي كما في المثال التالي:
والقسم الثاني من مدخلات الدالة يسمى مدخلات اختيارية. بحيث تعطى هذه المدخلات قيم افتراضية عند تعريف الدالة باستخدام علامة اليساوي "=". وعند استدعاء الدالة يمكن للمبرمج استبدال القيم الافتراضية بقيم جديدة والا قام مفسر بايثون باستخدام القيم الافتراضية التي تم كتابتها داخل قوسي الدالة وقت تعريفها كما في المثاليين التاليين:
ولكي نوضح الفرق بين هذين االنوعين من المدخلات للننظر للمثال التالي:
File "/tmp/ipykernel_28940/4098089560.py", line 1
def addition(y=4,x):
^
SyntaxError: non-default argument follows default argument
القسم الثالث من مدخلات الدالة يسمى المدخلات المرنة. ما ذا لو أننا أردنا كتابة دالة بحيث نعطي المستخدم حريته في اختيار عدد المدخلات التي يود معالجتها كأن تكون لدينا دالة تقوم بحساب حاصل ضرب القيم التي ندخلها لها بحيث يمكن أن يكون عدد القيم المدخلة 2 أو 3 أو 4 أو أي عدد من القيم الذي يختاره المستخدم فماذا عسانا أن نعمل.
لم يغفل مبرمجوا لغة بايثون عن هذه الخاصية ووضعوا تركيباً يمكّن مفسر بايثون من تعريف دالة ٍ مرنة المدخلات الإلزامية باستخدام علامة النجمة قبل اسم المدخل كما هو موضح في المثال التالي:
يجب ملاحظة ان المدخل الألزامي المرن يتم التعامل معه على أنه قائمة أو مصفوفة كما هو موضح في المثال السابق.
كما يمكن تعريف دالة بمدخلات اختيارية مرنة من خلال وضع علامتي نجمة أمام المتغير الذي سوف يمثل عدد المتغيرات الاختيارية كما في المثال التالي:
يجب ملاحظة أن المدخلات الاختيارية المرنة يتم التعامل معها على أنها قاموس كما هو موضح في المثال السابق.
مخرجات الدوال
مجال المتغيرات داخل الدوال
المتغير z في الدالة السابقة تم مسحه من الذاكرة بمجرد أن تم الإنتهاء من تنفيذ الدالة لذلك تسمى هذه المتغيرات بالمتغيرات المحلية أما المتغيرات التى تقع خارج الدوال فتسمى متغيرات عالمية (global variables) بحيث تحتفظ بقيمتها في أي مكان من البرنامج حتى لو كانت في داخل الدوال كما في المثال التالي
الدوال الداخلية
كما يجب الإشارة الى أنه بالإمكان إستدعاء دالة من داخل دالة كما في المثال التالي:
وكذلك يمكن تعريف دالة داخل دالة ولكن يجب استدعاء الداخلية من داخل الدالة الأم وإلاّ سوف يتم مسح تعريف الدالة الداخلية من ذاكرة الكمبيوتر بعد الإنتهاء من تنفيذ كود الدالة الأم كما في المثالين التاليين:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_28940/2232286928.py in <module>
3 print("I am inner2")
4 outer2()
----> 5 inner2()
NameError: name 'inner2' is not defined
في المثال الأول تم تعريف الدالة inner داخل الدالة outer وتم استدعاء الدالة inner من داخل الدالة الأم outer فتم تنفيذ الكود البرمجي الذي يقع داخل الدالة الداخلية inner. في المثال الثاني تم تعريف الدالة الداخلية inner2 داخل الدالة الخارجية outer2 لكن عملية الإستدعاء تمت من خارج الدالة الأم لذلك عندما انتهى مفسر بايثون من تنفيذ الدالة الأم التي بداخلها تعريف الدالة الداخلية inner2 تخلص مفسر بايثون من جميع المتغيرات المحلية ومن ضمنها تعريف الدالة inner2. لذلك عندما قمنا باستدعاء الدالة الداخلية inner لم يجد مفسر بايثون أي ا ثر للدالة الداخلية وأعطانا رسالة تفيد بعدم وجود المتغير inner2.
يمكن تجاوز هذه المشكلة بحيث يمكننا استدعاء الدالة التي تم تعريفها من داخل دالة اخرى بتكون متغير عالمي داخل الدالة الأم ومن ثم نقوم باسناد الدالة الداخلية لهذا ا لمتغير بحيث يمكننا استدعائها من خارج الدالة الأم كما في المثال التالي:
كما يجب الإشارة الى أنه بالإمكان ارجاع الدالة الداخلية كناتج للدالة الخارجية باستخدام العبارة return كما هو موضح في المثال التالي:
ويمكن كتابة المثال السابق بطريقة اخرى كما في المثال التالي:
الطريقة المختصرة لكتابة الدوال
بالإضافة الى الطريقة التلقيدية التي تناولنهاها بشيئ من التفصيل هناك طريقة مختصرة لكتابة الدوال باستخدام العبارة lambda كما هو موضح في المثال التالي:
فالتركيب اللغوي لكتابة الدوال المختصرة يبدأ بكتابة العبارة lambda متبوعاً بالمدخلات التي سوف تدخل في العمليات التي سوف تجريها الدالة. تنتهي المدخلات بنقطتين فوق بعض يكتب بعدها العمليات التي يود المبرمج إجراءها داخل الدالة. يمكن هذا التركيب من كتابة الدالة بدون اسم فيطلق عليها احياناً الدالة الغامضة anonymous function ويمكن ايضاً ان يسند هذا التركيب لمتغير يشير الى هذه الدالة كما فعلنا في المثال السابق باسناد الدالة التربيعية الى المتغير f. ويتم تنفيذ الدالة المختصرة بنفس الطريقة التقليدية التي تعلمناها سابقاً بأن توضع المدخلات بين قوسين بعد اسم المتغير الذي يشير الى الدالة المختصرة.
ويمكن التأكد من أن المتغير f أصبح يشير الى دالة باستخدام الدالة type كما هو موضح في المثال التالي:
لاستخدام أكثر من مدخل في الدالة المختصرة يفصل بين المدخلات بفاصلة كما تعلمنا سابقاً كما هو موضح في المثال التالي:
لاحظ أن ترتيب المدخلات وقت تنفيذ الدالة مهم كما تعلمنا سابقاً مع الدوال التقليدية.