دورة Python للمبتدئين

6: البرمجة بلغة بايثون – Functions الدوال

Python3.8

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

في هذا الدرس سنتعرف على الدوال، الفائدة منها و كيفية إنشائها:

ما هي الدوال؟

تسمح لنا الدوال بجمع أوامر برمجية تحت اسم واحد بهدف إعادة استعمالها.

تحتوي بايثون على عدة دوال مُعَرَّفة مسبقا، على سبيل المثال max (تقوم بإرجاع أكبر قيمة) و min (تقوم بإرجاع أصغر قيمة)، إذ لكل دالة دور معين يتم إنجازه باتباع الأوامر المُتَضَمَّنَة داخلها.

لماذا قد نستعمل الدوال؟

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

لتجنب هذا التكرار، نقوم ببساطة بإنشاء دالة تجمع تلك الأوامر، و عندما نستدعيها بكتابة اسم الدالة، يتن تنفيذ تلك الأوامر ببساطة. و تعتبر الدوال مفهوما رئيسيا جدا في لغات البرمجة لدورها المهم.

كيفية إنشاء دالة ما؟

لإنشاء دالة، نتبع الأسلوب التالي:

def name_of_function(Parameter1,Parameter2,Parameter3):
    p = 1 #نكتب الأوامر هنا

def هو اختصار لكلمة define بالإنجليزية و التي تعني عَرِّف. أي أنها الكلمة المفتاح التي تسمح بتعريف/إنشاء دالة ما. بجوارها نكتب اسم الدالة و الذي يجب أن يحترم نفس شروط كتابة أسماء المتغيرات.

بين القوسين يتم كتابة المعاملات أو parameters و هي ببساطة متغيرات تُستعمل في الأوامر الداخلية للدالة. و قد لا تحتوي الدالة على أي معامل كما قد تحتوي على عدة معاملات.

ثم أسفل الاسم، نكتب الأوامر التي ستتضمنها الدالة الخاصة بنا.

لنأخذ على سبيل المثال التطبيق الثاني في الدرس التطبيقي السابق:

a = input('Please enter a random number: ')
a = int(a)
for i in range(0,10):
    a += 1
    print(a)

لنقم الآن بكتابة دالة تحتوي على هذه الأوامر و بمجرد استدعائها يتم تنفيذ الشفرة:

def calc():
    a = 0
    for i in range(0,10):
        a += 1
        print(a)

calc()

ملاحظات:

  • عندما نكتب دالة ما، فإنه لا يتم تنفيذها إلا عندما نناديها أو نطلبها و ذلك من خلال كتابة اسم الدالة و معاملاتها parameters في حالة تواجدهم.
  • في المثال أعلاه، يتم تنفيذ الدالة تبعا لطلبنا في السطر 7 ، من خلال كتابة calc()
  • يجب الانتباه أيضا إلى الأقواس، فهي ضرورية في الدوال و يجب كتابتها دوما حتى و لو لم تحتوي الدالة على معاملات.
  • الدالة في الأعلى ستظهر دائما نتيجة متشابهة لأن المتغير a ثابت في هذه الحالة و يساوي دائما العدد 0.

ماذا لو أردنا تغيير قيمة المتغير a ؟

يمكن كتابة الكود على الشكل التالي:

def calc(a):
    for i in range(0,10):
        a += 1
        print(a)

calc(2)

ملاحظات:

وضعنا المتغير a بين قوسي الدالة calc ، مما يجعله الآن مُعَامِلا للدالة (parameter).

عندما نطلب الدالة، يجب أن نكتب رقما بين القوسين و إلا فسيظهر هذا الخطأ:

إذ توضح هذه الرسالة أن هناك عنصر مفقود و هو ‘a’ . لذا يجب كتابة المعامل بين القوسين.

ماذا لو لم يُدخل المستخدم مُعامِلا بين قوسي الدالة؟

يمكن كتابة معامل افتراضي default parameter حيث يتم استعماله في حالة لم يدخل المستخدم قيمة ما.

و ذلك كالتالي:

def calc(a=3):
    for i in range(0,10):
        a += 1
        print(a)

calc()

حيث قمنا بكتابة المعامل أو المتغير و أدخلنا فيه القيمة 3 باستعمال الرمز = .

عند تنفيذ هذه الشفرة، تظهر النتيجة التالية:

إذا نلاحظ بوضوح أن الشفرة نُفِّذَت دون مشاكل و أن القيمة التي تم استعمالها هي القيمة الافتراضية 3.

في حالة إدخال قيمة مختلفة في معامل الدالة:

def calc(a=3):
    for i in range(0,10):
        a += 1
        print(a)

calc(5)

عند التنفيذ، تظهر النتيجة التالية:

يبدأ العد من 6، إذا فالقيمة المُستعملة هي 5 التي قمنا بإدخالها سابقا!

إضافة معامل آخر:

لنأخذ التطبيق الخاص بجدول الضرب الذي رأيناه سابقا. إذا أردنا أن نحدد العدد الذي سنضرب فيه رقما ما عوض العدد 10 فقط، يمكن أن نستعمل الطريقة التالية:

def table(number, p=11):
    for i in range(1,p):
        print(number,'x',i,'=', number*i)

عند إدخال الرقم الذي نريد أن نحسب جدول ضربه، مثلا 5، ستظهر النتيجة كالتالي:

عندما نُدخل كلا من الرقم و رقم الأعداد الذي نريد أن يتم ضربه فيها، نكتب ببساطة كلا المعاملين:

  • في الكتابة التالية، يجب احترام نفس ترتيب المعاملات:
  • في الكتابة التالية، لا يؤثر الترتيب على المعاملات:

و هذا لأننا نعيد كتابة المعامل و نُدخل فيه القيمة باستعمال الرمز = ، فالترتيب هنا لا يؤثر.

ماذا لو كتبنا المعامل ذو القيمة الافتراضية قبل المعامل العادي في الدالة؟

عند كتابة الشفرة بالطريقة التالية، أي كتابة المعامل الافترضي p = 11 قبل المعامل العادي number :

def table(p=11, number):
    for i in range(1,p):
        print(number,'x',i,'=', number*i)

table(5)

ستظهر الرسالة التالية:

و كما نلاحظ في الرسالة، فهي تنبهنا إلى أننا قمنا بكتابة معامل عادي بعد معامل افتراضي.

لذا عند كتابة المعاملات الافتراضية في الدوال، يجب الانتباه إلى هذا الأمر و كتابة المعاملات الافتراضية بعد المعاملات العادية في حالة تواجد كلا النوعين.

ملاحظة:

يجب الانتباه في المثال أعلاه أننا نستعمل الحلقة for و الدالة range، حيث أن العدد الثاني في الدالة range غير مُتَضمَّن في الحلقة، لذا لا بد من إضافة رقم واحد إلى العدد دائما.

يمكن تجنب هذا باستعمال الحلقة while بالطريقة التالية:

def table(number, p=10):
    i = 0
    while i <= p:
        print(number,'x',i,'=', number*i)
        i += 1

table(5)

ما الفرق بين Parameter و Argument في الدوال؟

الـ parameter هو متغير مُرتبط بالدالة المعرفة، فمثلا في المثال أعلاه لدينا المتغير number و هو parameter خاص بالدالة table .

أما argument فهي القيمة التي يحملها الـ parameter. مثلا في المثال أعلاه، يحمل المتغير number القيمة 5 ( عندما طلبنا الدالة، أدخلنا القيمة 5 كالتالي: table(5) ) .

نقطة تشابه بين الدوال و المتغيرات:

عندما نُعرِّف دالة ما، و نُعرف دالة أخرى تحت نفس اسم الدالة الأولى، فإن المترجم يحذف محتوى الدالة الأولى و يحتفظ بمحتوى الدالة الثانية، ذلك أن لهما نفس الاسم و كتابة دالة أخرى حت نفس الاسم يستلزم حذف السابقة.

و هذا أمر ينطبق على المتغيرات أيضا:

أمر return

لكي نفهم هذا الأمر أو statement ، يجب أن نقارن بينه و بين الأمر print.

الأمر print يقوم بإظهار نتيجة للمستخدم توضح ما تفعله الدالة. بحيث لا يقوم هذا الأمر بحفظ تلك النتيجة في مساحة معينة مخصصة (كالمتغيرات مثلا).

و لكن الأمر return يقوم بحفظ تلك النتيجة من أجل استعمالها لاحقا، و هذا ما يميز هذا الأمر.

فالدوال دائما ما تقوم بإرجاع نتيجة معينة، كيفما كانت. في حالة لم نستعمل الأمر return أو yield (سنتطرق له لاحقا)، فإن النتيجة التي تُرجعها الدالة هي None أي لا شيء.

في المثال البسيط التالي يتضح الأمر أكثر:

def square_root(a):
     return (a * a)

def result(a):
    print('The square root of',a,'is',square_root(a))

result(2)

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

عند استعمال الأمر return في مكان print، تظهر النتيجة كالتالي عند طلب الدالة result(2):

نلاحظ أن الدالة اشتغلت بشكل صحيح و ظهرت النتيجة 4 كما يجب، إذا فقد قام الأمر return بحفظ النتيجة 4 من أجل الاستعمال اللاحق.

أما عندما نكتب print عوض return، فالنتيجة ستكون مختلفة:

def square_root(a):
     print (a * a)

def result(a):
    print('The square root of',a,'is',square_root(a))

result(2)

تمت طباعة الرقم 4 و هو الجذر التربيعي لـ 2، و بعدها تم إظهار الرسالة و لكن عوض كتابة النتيجة 4 تمت كتابة None، و كما قلنا سابقا، فإن استعمال print لا يحفظ النتيجة و يقوم بإرجاع None عند استعمال الدالة من طرق دوال أخرى.

لذا من المفضل استعمال الأمر return خاصة عندما نحتاج إلى استعمال الدالة ضمن دوال أخرى أو في عمليات أخرى.

دوال lambda:

دوال lambda هي دوال تتميز باقصرها و اختصارها مقارنة بالدوال المُعَرفة بواسطة الكلمة المفتاحية def.

فكلمة lambda تسمح لنا بإنشاء دوال أيضا، بطريقة مختصرة و سريعة.

مثال:

لنكتب دالة تحسب مُربع عدد ما:

lambda x: x * x

عندما نضغط على Enter في المترجم، تظهر الرسالة التالية:

إذا أردنا أن نستدعيها، لا بد أن نُخزن الدالة في متغير ما، على عكس الدوال المعرفة بـ def.

a = lambda x : x * x

و من أجل حساب مربع العد 5 مثلا، نكتب الرقم 5 بين قوسي المتغير a الذي يحتوي على الدالة:

في حالة رغبنا في استعمال أكثر من عامل parameter ، كمثال، نرغب في حساب ضرب عددين، نكتب الدالة كالتالي:

إذا، نستنتج أن الدالة lambda تُكتب بالطريقة التالية:

variable = lambda parameter1, parameter2, parameter3... : instructions 

ما الفائدة من دوال lambda و متى نستعملها؟

تتميز الدوال lambda بأنها دوال مجهولة anonymous لأنها لا ترتبط بالضرورة باسم ما. كما أنها تستطيع أن تشمل فقط تعبيرا expression واحدا. فهي قصيرة و مختصرة. و قد يكون استعمالها أفضل من استعمال الدوال المعرفة بـ def في حالات معينة.

نهاية الدرس الخامس

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

نُرحب بأية استفسارات أ, انتقادات في قسم التعليقات أسفل الموضوع.

السابق
5,5: البرمجة بلغة بايثون – مناقشة التطبيقات/التمارين
التالي
دورة شاملة في لغة البرمجة جافا|Overview