python 101 تعرف على الدوال (Functions) في بايثون


عبدالهادي الديوري

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

python-functions.png.61fc5c3079a4992a338

للتذكير: جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون.

الدوال

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

لنعتبر بأنّ طباعة جملة "Hello" هي الشيفرة التّي تحملها الدّالة، انظر المثال التّالي:

>>> def say_hello():
...    print "Hello"
...
>>> say_hello()
Hello

أولا قمنا بإنشاء الدّالة say_hello في السّطر:

def say_hello():

النّقاط الثّلاثة التّي تظهر بعد ذلك السّطر تعني بأن مُفسر بايثون ينتظر مدخلات أخرى، لذلك ندخل شيفرة الطّباعة (تذكر بأن هذه هي الشيفرة الأساسيّة) بعد مساحة بيضاء (أربع مسافات).

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

>>> say_hello()

ما رأيناه قبل قليل هو كيفية تعريف دالة، كيفية وضع شيفرة داخلها ثم كيفية استدعائها لتنفذ الشيفرة. يُمكن أن نجعل الدالة تُعيد قيمة دون تنفيذ أي شيفرة (رغم أنّها تُنفذ شيفرة الإرجاع)، انظر المثال التالي:

>>> def x():
...    return 4
...
>>> x()
4

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

ملاحظة حول تسمية الدوال

رغم أنك تستطيع تسمية الدوال بأحرف صغيرة وكبيرة معا، من المُفضل تسمية الدالة بأحرف صغيرة والفصل بين كل كلمة والأخرى بمحرف "_".

المعاملات Parameters

من مُميزات الدوال أنّك تستطيع أن تُعطيها مُعاملات عند تعريفها، وأن تُعطي القيم لهذه المُعاملات إما عند تعريف الدالة (المعاملات الافتراضية) أو لاحقا. 

لتفهم أكثر، انظر المثال التالي:

>>> def say_hello(name):
...     print 'Hello', name
... 
>>> say_hello('Abdelhadi')
Hello Abdelhadi
>>> say_hello('Hsoub Academy')
Hello Hsoub Academy

كما ترى لقد قُمنا بتعريف الدالة say_hello مع مُعامل name ووضعنا داخلها جملة طباعة لتطبع Hello متبوعا بقيمة العامل name بعدها قُمنا باستدعاء الدالة وأسندنا للعامل name قيمتين مُختلفتين، وقد كانت النتائج مُختلفة، يُمكنك أن تستدعي نفس الدالة مع معاملات مُختلفة لعدد غير محدود من المرات.

يُمكنك كذلك أن تقوم بتعريف دالة مع أكثر من معامل، إليك مثالا على دالة لإعادة مجموع عددين :

>>> def add_numbers(n1, n2):
...     return n1 + n2
... 
>>> add_numbers(3,4)
7

إذا قُمنا بتعريف دالة مع معامل فلا بد أن نقوم بتعيين قيمة العامل عند الاستدعاء وإلا فسيرجع مُفسر Python خطأ كالتّالي:

>>> say_hello()
TypeError: say_hello() takes exactly 1 argument (0 given)

الأمر نفسه يحدث إذا عينت عددا أكثر من العوامل المُفترض، مثلا أن تعطي للدالة say_hello مُعاملين أو أكثر. 

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

>>> def num(n1, n2 = 10):
...     return n1 + n2
... 
>>> num(3)
13

يُمكن أن تستعمل هذه الطريقة لعرض خطأ للمُستخدم إذا نسي إدخال المُعاملات.

>>> def say_hello(name = '| Error! Check the line that calls the function'):
...     print 'Hello', name
... 
>>> say_hello()
Hello | Error! Check the line that calls the function

يُمكنك كذلك أن تقوم بعدة عمليات مع الدوال، وإليك قائمة ببعض هذه العمليات:

تعريف دالة داخل دالة أخرى

بما أن الدوال عبارة عن أجزاء من الشيفرة فتستطيع أن تقوم بإنشاء دالة أخرى أو عدد من الدوال داخل الدالة الواحدة، انظر المثال التالي:

>>> def say_hello(name):
...     def hello():
...         return 'Hello '
...     print hello() + name
... 
>>> say_hello('Abdelhadi')
Hello Abdelhadi

كما ترى أعلاه القيمة Hello ما هي إلا القيمة التي أرجعتها الدالة hello المعرفة بداخل الدالة say_hello.

استدعاء دالة داخل دالة أخرى

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

>>> def say_hello(name):
...     print 'Hello', name
... 
>>> def print_hello():
...     say_hello('Abdelhadi')
... 
>>> print_hello()
Hello Abdelhadi

في المثال أعلاه قُمنا باستدعاء الدالة say_hello من داخل الدالة print_hello.

إسناد دالة لمتغير

تستطيع أن تُنشئ دالة وتقوم بإسنادها لمُتغير بالطّريقة التالية:

>>> def say_hello(name):
...     print 'Hello', name
... 
>>> s = say_hello
>>>> s('Abdelhadi')
Hello Abdelhadi

إسناد دالة كمعامل لدالة أخرى

قلنا مُسبقا بأنّه يمكن للدالة أن تتصرف كمتغير وذلك عندما نجعلها ترجع قيمة بالجملة return. وهذا يعني بأنّنا نستطيع أن نسند للدالة دالة أخرى.

>>> def say_hello(name):
...     print 'Hello', name
... 
>>> def get_name():
...     return 'Abdelhadi'
... 
>>> say_hello(get_name())
Hello Abdelhadi

إرجاع دالة داخل دالة أخرى

يُمكنك أيضا أن تستعمل الجملة return لإرجاع دالة داخل دالة أخرى عوضا عن إرجاع قيمة ما، انظر المثال:

>>> def get_hello():
...     return 'Hello Abdelhadi'
... 
>>> def say_hello():
...     return get_hello()
... 
>>> print say_hello()
Hello Abdelhadi

ستلاحظ بأنّ الدالة say_hello تحمل قيمة الدالة get_hello، وذلك لأنّنا أرجعنا هذه الأخيرة داخل الدالة say_hello.

إسناد عدد لا نهائي من المعاملات لدالة ما

لنقل بأنّك تريد أن تقوم بإنشاء دالة تطبع جميع المُحتويات (المُعاملات) التي تُدخلها دون الحاجة إلى تحديد كل معامل على حدة. يُمكنك أن تقوم بالأمر بما يُسمى مُعامل طول المُتغير أو Variable-length argument وذلك كالتالي:

>>> def print_arguments(*args):
...     print args
... 
>>> print_arguments(2, 4, 8, 'Abdelhadi', 'Hsoub Academy')
(2, 4, 8, 'Abdelhadi', 'Hsoub Academy')

المُتغير args عبارة عن صف (Tuple) من القيم، وبالتالي فإنك تستطيع أن تتعامل معه بحلقة For.

يُمكن أن تستخدم أي اسم نريده لهذا المعامل، وعموما يعتبر الاسم args* تقليدا بين مُبرمجي بايثون.

لاحظ أن الاختلاف بين المعامل العادي والمعامل في المثال أعلاه هو النجمة في البداية.

تستطيع أن تجعل المُعاملات قاموسا عوضا عن صف بحيث تُرجع الدالة القاموس الذي يحتوي على اسم المعامل وقيمته، وذلك كالآتي:

>>> def print_keyword_args(**kwargs):
...     print kwargs
... 
>>> print_keyword_args(name = 'Abdelhadi', website = 'Hsoub Academy', n = 3)

{'website': 'Hsoub Academy', 'name': 'Abdelhadi', 'n': 3}

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

المتغيرات المحلية والمتغيرات العامة Local variables and Global variables

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

>>> def say_hello():
...     name = 'Abdelhadi'
...     print 'Hello', name
... 
>>> say_hello()
Hello Abdelhadi
>>> print name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'name' is not defined

قُمنا بتعريف المُتغير name داخل الدالة say_hello وبعدها حاولنا الوصول إليه خارج الدالة، ما أدى إلى خطأ مفاده بأن مُفسر بايثون لم يتعرف على المُتغير.

يُمكن أن نجعل المتغير name عامًا بإضافة الكلمة global قبله (عليك أن تقوم بهذا قبل إسناد قيمة للمُتغير)، انظر المثال التالي:

>>> def say_hello():
...     global name
...     name = 'Abdelhadi'
... 
>>> say_hello()
>>> print name
Abdelhadi

نُلاحظ بأنّنا استطعنا الوصول إلى المُتغيّر name خارج الدالة التي عُرّفَ بها.

تطبيق

سنضرب مثالا بالبرنامج الذي أنشأناه في درس التعابير الشرطية والإزاحات.

print 'Hello User, this is a basic sign up/login Program'
username = raw_input('Enter your username please: ')
password = raw_input('Enter the your password please: ')
password_verification = raw_input('Verify password: ')
if password == password_verification:
    print 'You have Successfully Signed up! \n'
    username_sign_in = raw_input('Enter your username please: ')
    password_sign_in = raw_input('Enter your password please: ')
    if username_sign_in == username and password_sign_in == password:
        print 'You have Successfully Signed in!'
    else:
        print 'username or password do not match! Please try again!'
else:
    print 'The password and the password verification do not match! Please try again'

سنركز على شيفرة التحقق من المُستخدم وكلمة المرور:

    if username_sign_in == username and password_sign_in == password:
        print 'You have Successfully Signed in!'
    else:
        print 'username or password do not match! Please try again!'

إذا أردنا أن نستخدمها لأكثر من مرة في برنامجنا فعلينا أن نضعها داخل دالة.

def user_logged_in?(username_sign_in, username, password_sign_in, password):
    if username_sign_in == username and password_sign_in == password:
        return True
    else:
        return False

يُمكنك استخدام الدالة في أي مكان من الشيفرة:

def is_user_logged_in(username_sign_in, username, password_sign_in, password):
    if username_sign_in == username and password_sign_in == password:
        return True
    else:
        return False

new_password = raw_input('Enter new username: ')
new_username = raw_input('Enter new password: ')
print 'Ok!'
password = raw_input('Hello again, Enter your username: ')
username = raw_input('Enter username\'s password: ')

print is_user_logged_in(username, new_username, password, new_password)

الدالة is_user_logged_in تقوم بمُقارنة كلمتي المرور واسمي المُستخدم فإن كانا متطابقين فستصبح قيمة الدالة True أما إن لم تتوافق القيم فإنّ الدالة تحمل القيمة False ويُمكنك الآن استخدام الدالة مع الجمل الشرطية في أي مكان من برنامجك دون الاضطرار لإعادة كتابة شيفرة التحقق كل مرة. كما أنّ التعديل على الشيفرة بسيط جدا، فالتّعديل من مكان واحد (الدالة) يكفي يطبّق على جميع الأماكن الأخرى (أمكنة استدعاء الدالة).

الدوال المعرفة مسبقا

تُوفر بايثون دوالا مُعرفة مُسبقا، وقد تعاملنا مع كثير منها في الدروس السابقة، وإليك بعض الدوال المُفيدة التي توجد مُسبقا بلغة بايثون.

  • print: دالة الطّباعة التي استخدمناها أكثر من مرة لطباعة القيم في سابق الدروس.
  • Int: دالة تحويل القيم إلى عدد صحيح، مثال:
>>> int(5.5)
5
  • str: دالة تحويل القيم إلى سلسلة نصيّة String:
>>> str(True)
'True'

وتُستعمل كثيرا لجمع سلسلة نصية بقيمة من نوع آخر بالعامل + (إذا لم تستخدم هذه الدالة فسيعرض لك مُفسر بايثون خطأ يُفيد بأنّك لا تستطيع جمع قيمتين من نوعين مُختلفين):

>>> print 'ABC' + str(122) + str(False)
ABC122False
  • abs: دالة للحصول على القيمة المُطلقة Absolute Value لعدد ما (إذا كان موجبا فهو العدد نفسه، وإذا كان سالبا فمُقابله):
>>> abs(3)
3
>>> abs(-3)
3
  • len: دالة لقياس عدد عناصر قائمة أو عدد أحرف سلسلة نصية.
>>> a = ['Abdelhadi', 'Dyouri', 'Academy', 'Hsoub']
>>> b = 'Hello'
>>> len(a)
4
>>> len(b)
5
  • min: دالة لتحديد أقل قيمة بين قيمتين أو أكثر.
>>> min(4, 5, 7, 88, 3, 2)
2
  • max: دالة لتحديد أقل قيمة بين قيمتين أو أكثر.
>>> max(4, 5, 7, 88, 3, 2)
88
  • range: لتوليد قائمة بأعداد بين قيمة المعامل الأول وقيمة المُعامل الثاني:
>>> range(0, 11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> range(0, 11, 3)
[0, 3, 6, 9]
  • raw_input: دالة للحصول على مُدخل نصي من المُستخدم، يُمكنك أن تسند هذا المُدخل إلى مُتغير.
>>> def say_hello(name):
...     print 'Hello', name
... 
>>> say_hello(raw_input())
Abdelhadi
Hello Abdelhadi

كما قُلنا سابقا، فإنك تستطيع أن تقوم بإسناد دالة كمعامل لدالة أخرى، وهذا ما فعلناه في المثال أعلاه، إذ مررنا الدالة raw_input ليكون معاملا للدالة say_hello.

تمارين

تمرين 1

اكتب برنامجا للحصول على قيمة من المُستخدم وتحويلها إلى قيمة عددية.

تمرين 2

اكتب دالة لطباعة جملة لعدد من المرات، واترك للمُستخدم حرية اختيار عدد مرات التكرار (مُساعدة: استعمل الدالة raw_input للحصول على قيمة من المُستخدم)

تمرين 3

اكتب دالة للجمع بين عددين يُدخلهما المُستخدم.

تمرين 4

بَرمِجْ آلة حاسبة بسيطة تقوم بالجمع، الطّرح، الضرب والقسمة. إليك طريقة العمل: 

  1. احصل على قيمة العدد الأول من المُستخدم. 
  2. احصل على قيمة العدد الثاني. 
  3. حول القيمتين النصيتين إلى قيمتين عدديتين. 
  4. احصل على العامل الرياضي (*، /، - أو +) من المُستخدم. 
  5. استخدم الجمل الشرطية لإجراء العملية المُناسبة (إذا كان المُدخل + فقم بالجمع).

ترجمة -وبتصرف- من الكتاب Python Practice Book لكاتبه Anand Chitipothu.



1 شخص أعجب بهذا


تفاعل الأعضاء


التمرين الثاني كيف حله ؟

شارك هذا التعليق


رابط هذا التعليق
شارك على الشبكات الإجتماعية


يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن