Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

بايثونالدوال

  • مفهوم الدوال
  • تعريف دوال جديدة
  • وضع قيم إفتراضية للباراميترات
  • تحديد أسماء الباراميترات التي سيتم إعطاءها قيم
  • بناء دوال تقبل عدد غير محدد من القيم
  • التفريق بين المتغيرات المعرفة بداخل الدوال و خارجها في بايثون
  • تعريف دوال بأسلوب Lambda

مفهوم الدوال

الدالة ( Function ) عبارة عن مجموعة أوامر مجمعة في مكان واحد و تتنفذ عندما يتم استدعائها.
بايثون تحتوي على مجموعة كبيرة جداً من الدوال الجاهزة و التي سبق أن إستخدامنا بعضها مثل الدوال print() و min() و max() و غيرهم من الدوال التي تطرقنا إليها في دروس سابقة.

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

الدوال الجاهزة في بايثون يقال لها Built-in Functions.
الدوال التي يقوم المبرمج بتعريفها يقال لها User-defined Functions.

تعريف دوال جديدة

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

def functionname():
    function_suite
  • def: نستخدمها لتعريف دالة جديدة.
  • functionname: مكانها نضع الإسم الذي نريد إعطاؤه للدالة، و الذي من خلاله يمكننا استدعاءها.
  • function_suite: تعني الأوامر التي سنضعها في الدالة و التي ستتنفذ عند إستدعائها.

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


في المثال التالي قمنا بتعريف دالة إسمها my_function وضعنا فيها أمر طباعة واحد فقط. بعدها قمنا باستدعائها.

المثال الأول

Test.py
# my_function هنا قمنا بتعريف دالة إسمها
def my_function():
    print('My first function is called')


# حتى يتنفذ الأمر الموضوع فيها my_function هنا قمنا باستدعاء الدالة
my_function()

النتيجة

My first function is called

معلومات إضافية يمكن ذكرها في الدالة

قبل قليل تكلمنا عن الأشياء الأساسية التي يجب أن تكون متوفرة عند تعريف أي دالة.
الآن، عليك معرفة أنه يمكنك وضع مزيد من التفاصيل بشرط أن تضيفها ضمن ترتيب محدد و ليس شرطاً أن تضيفها كلها.

def functionname(parameters):
    """ docstring """
    function_suite
    return [expression]
  • parameters: مكانها يمكن وضع متغيرات، و هذه المتغيرات نمرر لها قيم عند استدعاء الدالة.
  • """ docstring """: مكانها يمكن وضع نص الهدف منه تفسير ما تفعله الدالة بشكل مختصر.
  • return: يمكن استخدامها لجعل الدالة ترجع القيمة التي نضعها بعدها إلى المكان الذي تم إستدعاءها منه.

هنا قمنا بتعريف دالة إسمها greeting، عند إستدعائها نمرر لها إسم فتطبع رسالة ترحيب للإسم الذي تم تمريره لها.

المثال الثاني

Test.py
# تحتوي على باراميتر واحد greeting هنا قمنا بتعريف دالة إسمها
#  عند إستدعائها نمرر لها إسم شخص، فتطبع جملة ترحيب بإسم الشخص الذي نمرره لها 
def greeting(name):
    """ This function print hello message based on the specified name """
    print('Hello '+name+', welcome to our company.')


# user هنا قمنا بتخزين إسم الشخص الذي سنمرره للدالة في المتغير
user = 'Ahmad'

# حتى تطبع رسالة ترحيب له user و تمرير إسم الشخص الذي قمنا بتخزينه في المتغير greeting() هنا قمنا باستدعاء الدالة
greeting(user)

النتيجة

Hello Ahmad, welcome to our company.

المتغير الذي يتم تعريفه بين أقواس الدالة يسمى باراميتر ( Parameter ).
الباراميتر يُعتبر متغيّر محلّي ( Local Variable ) بالنسبة للدالة حيث أنه لا يمكن الوصول إليه من خارجها.


هنا قمنا بكتابة نفس الدالة السابقة لكننا قمنا هذه المرة بطباعة الشرح الموضوع في الدالة ( أي الـ doc string ) و ليس إستدعاءها.

المثال الثالث

Test.py
# تحتوي على باراميتر واحد greeting هنا قمنا بتعريف دالة إسمها
# عند إستدعائها نمرر لها إسم شخص، فتطبع جملة ترحيب بإسم الشخص الذي نمرره لها 
def greeting(name):
    """ This function print hello message based on the specified name """
    print('Hello '+name+', welcome to our company.')


# greeting() هنا قمنا بطباعة الشرح المرفق بالدالة
print(greeting.__doc__)

النتيجة

This function print hello message based on the specified name

في المثال التالي قمنا بتعريف دالة إسمها get_sum، عند إستدعائها نمرر لها عددين فترجع لنا ناتج جمعهما.

المثال الرابع

Test.py
# عند إستدعائها نمرر لها عددين فتقوم بإرجاع ناتج جمعهما get_sum هنا قمنا بتعريف دالة إسمها
def get_sum(a, b):
    """This method returns the sum of the numbers that you passed in a and b"""
    return a + b;


# x في المتغير get_sum() هنا قمنا بتخزين ناتج جمع العددين 3 و 5 الذي سترجعه الدالة
x = get_sum(3, 5)

# و التي تساوي 8 x هنا قمنا بعرض قيمة المتغير
print(x)

النتيجة

8

وضع قيم إفتراضية للباراميترات

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

القيمة الإفتراضية التي يتم وضعها للباراميتر يقال لها Default Value أو Default Argument.


في المثال التالي قمنا بتعريف دالة إسمها print_language.
هذه الدالة فيها باراميتر واحد إسمه language و يملك النص 'English' كقيمة إفتراضية.

ملاحظة: كل ما تفعله هذه الدالة عند إستدعائها هو طباعة قيمة الباراميتر language، و بما أنه يملك قيمة إفتراضية فهذا يعني أننا غير مجبرين على تمرير قيمة له عند إستدعاء الدالة لأنه أصلاً يملك قيمة.

مثال

Test.py
# عند إستدعائها يمكنك تمرير قيمة ،print_language هنا قمنا بتعريف دالة إسمها 
# و يمكنك عدم تمرير قيمة لأنه أصلاً يملك قيمة language لها مكان الباراميتر 
def print_language(language='English'):
    print('Your language is:', language)


# بدون تمرير قيمة print_language() هنا قمنا باستدعاء الدالة
# 'English' و بالتالي ستظل قيمته language قيمة مكان الباراميتر
print_language()

# مع تمرير القيمة print_language() هنا قمنا باستدعاء الدالة
# 'Arabic' و بالتالي ستصبح قيمته language للباراميتر 'Arabic' 
print_language('Arabic')

النتيجة

Your language is: English
Your language is: Arabic

تحديد أسماء الباراميترات التي سيتم إعطاءها قيم

في أغلب لغات البرمجة عندما إستدعاء دالة تحتوي على عدة باراميترات فإنه يجب تمرير قيم لهذه الباراميترات بنفس الترتيب الذي تم وضعهم فيه.

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

في المثال التالي قمنا بتعريف دالة إسمها print_info تحتوي على باراميترين هما name و salary.

بعدها قمنا باستدعائها مرتين و لكن بطرق مختلفة:

  • أول مرة، قمنا بتمرير قيم للباراميترات بالترتيب الذي تم وضعهم فيه
  • ثاني مرة، قمنا بتمرير نفس القيم للباراميترات و لكن بدون التقيد بالترتيب الموضوعين فيه

مثال

Test.py
# عند إستدعائها يجب أن print_info هنا قمنا بتعريف دالة إسمها
# salary و قيمة مكان الباراميتر name نمرر لها قيمة مكان الباراميتر 
def print_info(name, salary):
    print('Name:', name)
    print('Salary:', salary)
    print('------------------')


# للباراميتر 'Nader' مع تمرير النص print_info() هنا قمنا بإستدعاء الدالة
# بنفس الترتيب الموضوعين فيه salary و العدد 1500 للباراميتر name 
print_info('Nader', 1500)

# مع تحديد أن العدد 1500 سيتم وضعه print_info() هنا قمنا بإستدعاء الدالة
# name سيتم وضعه في الباراميتر 'Nader' و النص salary في الباراميتر 
print_info(salary=1500, name='Nader')

النتيجة

Name: Nader
Salary: 1500
------------------
Name: Nader
Salary: 1500
------------------

بناء دوال تقبل عدد غير محدد من القيم

في بعض الأحيان قد تحتاج إلى بناء دالة تعالج عدد غير محدد من القيم عند استدعائها، أي مهما كان عدد القيم التي ستمررها لها فإنها يجب أن تعالجهم كلهم.

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

في حال كان عدد القيم التي يمكن تمريرها للباراميتر غير محدد يقال لهذه القيم Variable-length Arguments.


في المثال التالي قمنا بتعريف دالة إسمها print_args تقبل عدد غير محدد من القيم عند إستدعائها بعدها تقوم فقط بعرض هذه القيم بواسطة الحلقة for.
جميع القيم التي سيتم تمريرها لها، سيتم تخزينها في باراميتر واحد إسمه *args.

المثال الأول

Test.py
# عند إستدعائها يمكننا تمرير عدد print_args هنا قمنا بتعريف دالة إسمها
# غير محدد من القيم لها. بعدها ستقوم بطباعة القيم التي مررناها لها 
def print_args(*args):
    for e in args:
        print(e)

        
# مع تمرير 10 قيم لها print_args() هنا قمنا بإستدعاء الدالة
print_args(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

النتيجة

1
2
3
4
5
6
7
8
9
10

في المثال التالي قمنا بتعريف دالة إسمها print_average تقبل عدد غير محدد من القيم عند إستدعائها.
الهدف من هذه الدالة طباعة متوسط القيم التي تم تمريرها إليها و الذي يساوي ناتج جمع القيم التي تمريرها مقسوماً على عددهم.
جميع القيم التي سيتم تمريرها لها، سيتم تخزينها في باراميتر واحد إسمه *values.

ملاحظة: قمنا بالإعتماد على الدوال الجاهزة في بايثون sum() و len() لنحصل على ناتج جمع القيم التي يتم تمريرها و عددهم.

المثال الثاني

Test.py
# عند إستدعائها يمكننا تمرير عدد print_average هنا قمنا بتعريف دالة إسمها
# غير محدد من القيم لها. بعدها ستقوم بطباعة متوسط القيم التي مررناها لها 
def print_average(*values):
    print(sum(values)/len(values))


# مع تمرير 4 قيم لها print_total() هنا قمنا بإستدعاء الدالة
print_average(1, 2, 3, 4)

النتيجة

2.5

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

  • القيمة الأولى تمثل إسم الشخص و الذي سنقوم بتخزينه في باراميتر إسمه user.
  • القيمة الثانية أو مجموعة القيم الثانية تمثل علامات هذا الشخص و التي سنقوم بتخزينها في باراميتر واحد إسمه *notes.

المثال الثالث

Test.py
# عند إستدعائها يجب أن نمرر لها print_user_average هنا قمنا بتعريف دالة إسمها
# و عندها ستقوم ،notes و علاماته مكان الباراميتر user إسم الشخص مكان الباراميتر 
# بحساب معدله ( بناءاً على علاماته ) و من ثم تعرض إسمه و معدله بشكل مرتب
def print_user_average(user, *notes):
    avg = sum(notes)/len(notes)
    print('The average of', user, 'is:', avg)


# مع تمرير إسم الشخص و 4 قيم ( علامات ) لها print_user_average() هنا قمنا بإستدعاء الدالة
print_user_average('Ahmad', 1, 2, 3, 4)

النتيجة

The average of Ahmad is: 2.5

التفريق بين المتغيرات المعرفة بداخل الدوال و خارجها في بايثون

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

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

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

المتغير الذي يتم تعريفه بداخل دالة يعتبر متغير محلي ( Local Variable ) و هو لا يمكن الوصول له بشكل مباشر من خارج الدالة.
المتغير الذي يتم تعريفه خارج الدالة يعتبر متغير عام ( Global Variable ) حيث أنه يمكن الوصول له من أي مكان في الكود و حتى من داخل الدوال.


في المثال التالي قمنا بتعريف متغير إسمه x، ثم قمنا بتعريف دالة إسمها test تقوم فقط بطباعة قيمته.

المثال الأول

Test.py
# قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
x = 1


# الذي تم تعريفه خارجها x تطبع قيمة المتغير test هنا قمنا بتعريف دالة إسمها
def test():
    print('Global x =', x)


# الذي تم تعريفه خارجها x و التي ستطبع قيمة المتغير test() هنا قمنا باستدعاء الدالة
test()

النتيجة

Global x = 1

في المثال التالي قمنا بتعريف متغير إسمه x, ثم قمنا بتعريف دالة إسمها test تحتوي أيضاً على متغير إسمه x و الهدف منها طباعة قيمته فقط.

المثال الثاني

Test.py
# قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
x = 1


# الذي تم تعريفه بداخلها x تطبع قيمة المتغير test هنا قمنا بتعريف دالة إسمها
def test():
    x = 5
    print('Local x =', x)


# الذي تم تعريفه بداخلها x و التي ستطبع قيمة المتغير test() هنا قمنا باستدعاء الدالة
test()

# الموجود خارج الدالة. لاحظ أن قيمته لم تتغير x هنا قمنا بطباعة قيمة المتغير
print('Global x =', x)

النتيجة

Local x = 5
Global x = 1

عند استدعاء الدالة test() تم طباعة قيمة x الذي تم تعريفه بداخلها و ليس الموجود خارجها لأن مفسّر لغة بايثون تجاهل المتغير الخارجي.


في المثال التالي قمنا بتعريف متغير إسمه x و قيمته 1، ثم قمنا بتعريف دالة إسمها test مهتمها فقط تغيير قيمته إلى 5.

المثال الثالث

Test.py
# قيمته تساوي 1 x هنا قمنا بتعريف متغير إسمه
x = 1


# الذي تم تعريفه خارجها x تقوم بتغير قيمة test هنا قمنا بتعريف دالة إسمها
def test():
    global x
    x = 5


# الذي قمنا x حتى تقوم بتغيير قيمة المتغير test() هنا قمنا باستدعاء الدالة
# global بتعريفه في الأساس خارجها و الذي وصلنا إليه بواسطة الكلمة 
test()

# الموجودة في خارج الدالة و لاحظ أنها بقيت كما هي x هنا قمنا بطباعة قيمة
print('Global x =', x)

النتيجة

Global x = 5

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

تعريف دوال بأسلوب Lambda

في حال كنت تريد تعريف دالة مجهولة الإسم ( Anonymous Function ) تتألف من سطر واحد فقط و ترجع قيمة عند إستدعائها فيجب استخدام الكلمة المفتاحية lambda لتعريفها و ليس الكلمة def.

الشكل الأساسي الذي يجب إتباعه عند تعريف دالة بأسلوب Lambda في بايثون هو التالي:

lambda [arg1 [,arg2, ...argn]]:expression
  • lambda: نستخدمها لتعريف دالة جديدة ليس لها إسم.
  • [arg1 [,arg2, ...argn]]: يقصد بها الباراميترات التي يمكن وضعها في الدالة مع الإشارة إلى أنه يجب وضع فاصلة بين كل باراميترين.
  • :expression: تعني الأمر الذي سيرجع القيمة عندما تتنفذ الدالة مع الإشارة إلى أنه يجب وضع الرمز : قبلها.

عندما تقوم بتعريف Anonymous Function فأنت فعلياً تقوم بتعريف دالة ليس لها إسم. و بما أنه لا يمكن إستدعاء دالة إلا من خلال مناداتها باسمها فالحل هو أن تشير للدالة بإسم متغير. أي تقوم بتعريف متغير و تجعله يساوي الدالة التي قمت بتعريفها و عندها سيتم إعتبار إسم المتغير هو إسم الدالة الذي من خلاله يمكن مناداتها.


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

مثال

Test.py
# هنا قمنا بتعريف دالة يجب أن نمرر لها قيمتين عند إستدعائها حتى
# total_pay ترجع ناتج طرحهما، و يمكن مناداتها بواسطة الكائن
total_pay = lambda price, tax: price - tax

# و كل ما total_pay هنا قمنا بإستدعاء الدالة بواسطة الكائن
# ستفعله هو إرجاع ناتج طرح القيمة الثانية من القيمة الاولى
print(total_pay(500, 40))

النتيجة

460