كيفية تعريف الدوال في Python 3

المقدمة

A function is a block of instructions that performs an action and, once defined, can be reused. Functions make code more modular, allowing you to use the same code over and over again.

يحتوي Python على عدد من الوظائف المدمجة التي قد تكون معروفة لديك، بما في ذلك:

  • print() الذي سيقوم بطباعة كائن إلى المحطة
  • int() الذي سيحول نوع بيانات سلسلة أو رقم إلى نوع بيانات صحيح
  • len() الذي يعيد طول كائن

أسماء الوظائف تتضمن الأقواس وقد تتضمن معلمات.

في هذا البرنامج التعليمي، سنتناول كيفية تعريف الوظائف الخاصة بك لاستخدامها في مشاريع البرمجة الخاصة بك.

المتطلبات المسبقة

يجب أن يكون لديك Python 3 مثبتًا وبيئة برمجة معدة على جهاز الكمبيوتر أو الخادم الخاص بك. إذا لم يكن لديك بيئة برمجية معدة، يمكنك الرجوع إلى دليل التثبيت والإعداد لـ بيئة برمجة محلية أو لـ بيئة برمجة على خادمك المناسبة لنظام التشغيل الخاص بك (أوبونتو، سنت أو إس، ديبيان، إلخ).

تعريف الدالة

لنبدأ بتحويل البرنامج الكلاسيكي “مرحبًا، العالم!” إلى دالة.

سنقوم بإنشاء ملف نصي جديد في محرر النص الذي نفضله، ونسمي البرنامج hello.py. ثم، سنقوم بتعريف الدالة.

A function is defined by using the def keyword, followed by a name of your choosing, followed by a set of parentheses which hold any parameters the function will take (they can be empty), and ending with a colon.

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

في هذه الحالة، سنقوم بتعريف دالة تسمى hello():

hello.py
def hello():

هذا يعيد البيان الأولي لإنشاء دالة.

من هنا، سنضيف سطرًا ثانيًا بمسافة فارغة بمقدار ٤ لتقديم التعليمات لماذا الدالة تقوم. في هذه الحالة، سنقوم بطباعة مرحبًا، العالم! إلى الوحدة النمطية:

hello.py
def hello():
    print("Hello, World!")

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

لذا، خارج كتلة الدالة المعرفة لدينا، دعونا نستدعي الدالة بـ hello():

hello.py
def hello():
    print("Hello, World!")

hello()

الآن، دعونا نشغل البرنامج:

  1. python hello.py

يجب أن تتلقى الناتج التالي:

Output
Hello, World!

يمكن أن تكون الوظائف أكثر تعقيدًا من وظيفة hello() التي قمنا بتعريفها أعلاه. على سبيل المثال، يمكننا استخدام حلقات for، البيانات الشرطية، وغير ذلك داخل كتلة الوظيفة الخاصة بنا.

على سبيل المثال، تستخدم الوظيفة المعرفة أدناه بيانًا شرطيًا للتحقق مما إذا كانت الإدخالات لمتغير name تحتوي على حرف متحرك، ثم تستخدم حلقة for لتكرار الحروف في سلسلة name.

names.py
# تحديد وظيفة names()
def names():
    # إعداد متغير name بإدخال
    name = str(input('Enter your name: '))
    # التحقق مما إذا كان لدى name حرف متحرك
    if set('aeiou').intersection(name.lower()):
        print('Your name contains a vowel.')
    else:
        print('Your name does not contain a vowel.')

    # تكرار على name
    for letter in name:
        print(letter)

# استدعاء الوظيفة
names()

الوظيفة names() التي قمنا بتعريفها أعلاه تعيد بيان شرطي وحلقة for، مما يظهر كيف يمكن تنظيم الكود داخل تعريف الوظيفة. ومع ذلك، يمكن أن نرغب، اعتمادًا على ما ننوي فعله ببرنامجنا وكيف نريد ترتيب الكود، في تعريف البيان الشرطي وحلقة for كوظائف منفصلة.

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

العمل مع المعلمات

حتى الآن، نظرنا إلى الوظائف التي تحتوي على أقواس فارغة ولا تأخذ معاملات، ولكن يمكننا تحديد المعلمات في تعريفات الوظائف داخل أقواسها.

A parameter is a named entity in a function definition, specifying an argument that the function can accept.

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

add_numbers.py
def add_numbers(x, y, z):
    a = x + y
    b = x + z
    c = y + z
    print(a, b, c)

add_numbers(1, 2, 3)

قمنا بتمرير الرقم 1 للمعلمة x، و 2 للمعلمة y، و 3 للمعلمة z. تتوافق هذه القيم مع كل معلمة في الترتيب الذي تم تحديده.

يقوم البرنامج في الأساس بالعمليات الحسابية التالية استنادًا إلى القيم التي قمنا بتمريرها إلى المعلمات:

a = 1 + 2
b = 1 + 3
c = 2 + 3

تقوم الوظيفة أيضًا بطباعة a، b، و c، واستنادًا إلى الرياضيات أعلاه يمكننا توقع أن a ستكون مساوية لـ 3، b لـ 4، و c لـ 5. لنقم بتشغيل البرنامج:

  1. python add_numbers.py
Output
3 4 5

عندما نقوم بتمرير 1، 2، و 3 كمعلمات إلى الوظيفة add_numbers()، نحصل على الإخراج المتوقع.

المعلمات هي الوسائط التي عادة ما تُعرَّف كمتغيرات داخل تعاريف الوظائف. يمكن تعيين قيم لها عند تشغيل الطريقة، مرسلًا الوسائط إلى الوظيفة.

الوسائط الرئيسية

بالإضافة إلى استدعاء المعلمات بالترتيب، يمكنك استخدام الوسائط الرئيسية في استدعاء الوظيفة، حيث يحدد الشخص الذي يستدعي الوظيفة الوسائط بواسطة اسم المعلمة.

عند استخدام الوسائط الرئيسية، يمكنك استخدام المعلمات بشكل غير متسلسل لأن مترجم Python سيستخدم الكلمات الرئيسية المقدمة لتطابق القيم مع المعلمات.

لنقم بإنشاء وظيفة ستعرض لنا معلومات الملف الشخصي لمستخدم. سنمرر لها المعلمات بصورة اسم_المستخدم (مقصودة كسلسلة نصية)، و المتابعون (مقصودة كعدد صحيح).

profile.py
# تعريف الوظيفة مع المعلمات
def profile_info(username, followers):
    print("Username: " + username)
    print("Followers: " + str(followers))

Dentro del enunciado de definición de la función, اسم_المستخدم و المتابعون يتم وضعهما في الأقواس لوظيفة profile_info(). يقوم كتلة الوظيفة بطباعة معلومات حول المستخدم كسلاسل نصية، مستخدمة المعلمتين.

الآن، يمكننا استدعاء الوظيفة وتعيين المعلمات لها:

profile.py
def profile_info(username, followers):
    print("Username: " + username)
    print("Followers: " + str(followers))

# استدعاء الوظيفة مع المعلمات المعينة كما هو موضح أعلاه
profile_info("sammyshark", 945)

# استدعاء الوظيفة بواسطة الوسائط الرئيسية
profile_info(username="AlexAnglerfish", followers=342)

في الدعوة الأولى للدالة، قمنا بملء المعلومات بمعرف المستخدم sammyshark وعدد المتابعين يكون 945، في الدعوة الثانية للدالة استخدمنا الوسائط الرئيسية، وقمنا بتعيين قيم لمتغيرات الوسيط.

لنقم بتشغيل البرنامج:

  1. python profile.py
Output
Username: sammyshark Followers: 945 Username: AlexAnglerfish Followers: 342

يظهر لنا الإخراج أسماء المستخدمين وأعداد المتابعين لكل منهم.

هذا أيضًا يتيح لنا تعديل ترتيب المعلمات، كما في هذا المثال على نفس البرنامج مع استدعاء مختلف:

profile.py
def profile_info(username, followers):
    print("Username: " + username)
    print("Followers: " + str(followers))

# تغيير ترتيب المعلمات
profile_info(followers=820, username="cameron-catfish")

عند تشغيل البرنامج مرة أخرى باستخدام أمر python profile.py، سنتلقى الإخراج التالي:

Output
Username: cameron-catfish Followers: 820

لأن تعريف الدالة يحتفظ بنفس ترتيب تعليمات print()، إذا استخدمنا الوسائط الرئيسية، فلا يهم أي ترتيب نمرره إليها في دعوة الدالة.

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

يمكننا أيضًا توفير قيم افتراضية لأحد أو كلا المعلمتين. دعونا نقم بإنشاء قيمة افتراضية للمعلمة followers بقيمة 1:

profile.py
def profile_info(username, followers=1):
    print("Username: " + username)
    print("Followers: " + str(followers))

الآن، يمكننا تشغيل الدالة مع تعيين دالة المعرف فقط، وسيتم تعيين عدد المتابعين تلقائيًا إلى 1. يمكننا أيضًا تغيير عدد المتابعين إذا أردنا.

profile.py
def profile_info(username, followers=1):
    print("Username: " + username)
    print("Followers: " + str(followers))

profile_info(username="JOctopus")
profile_info(username="sammyshark", followers=945)

عند تشغيل البرنامج بأمر python profile.py، سنتلقى الإخراج التالي:

Output
Username: JOctopus Followers: 1 Username: sammyshark Followers: 945

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

إرجاع قيمة

يمكنك تمرير قيمة معلمة إلى دالة، ويمكن لدالة أيضًا أن تنتج قيمة.

A function can produce a value with the return statement, which will exit a function and optionally pass an expression back to the caller. If you use a return statement with no arguments, the function will return None.

حتى الآن، لقد استخدمنا البيان print() بدلاً من البيان return في وظائفنا. دعونا ننشئ برنامجًا سيعيد قيمة متغير بدلاً من الطباعة.

في ملف نصي جديد يسمى square.py، سننشئ برنامجًا يقوم بتربيع المعلمة x ويعيد المتغير y. نقوم بالدعوة لطباعة المتغير result، الذي يتم تشكيله من خلال تشغيل دالة square() بتمرير 3 إليها.

square.py
def square(x):
    y = x ** 2
    return y

result = square(3)
print(result)

يمكننا تشغيل البرنامج واستلام الناتج:

  1. python square.py
Output
9

يتم إرجاع العدد الصحيح 9 كنتيجة، وهو ما نتوقعه عند طلب Python لإيجاد تربيع العدد 3.

لفهم كيف يعمل البيان return بشكل أعمق، يمكننا تعليق البيان return في البرنامج:

square.py
def square(x):
    y = x ** 2
    # return y

result = square(3)
print(result)

الآن، دعونا نشغل البرنامج مرة أخرى:

  1. python square.py
Output
None

بدون استخدام بيان return هنا، لا يمكن للبرنامج إرجاع قيمة لذا تكون القيمة افتراضيًا None.

كمثال آخر، في البرنامج add_numbers.py أعلاه، يمكننا استبدال التعليمة print() بتعليمة return.

add_numbers.py
def add_numbers(x, y, z):
    a = x + y
    b = x + z
    c = y + z
    return a, b, c

sums = add_numbers(1, 2, 3)
print(sums)

خارج الدالة، نعين المتغير sums بالقيمة المُعادة من الدالة باستخدام 1 و 2 و 3 كما فعلنا سابقًا. ثم قمنا بطباعة المتغير sums.

دعنا نقوم بتشغيل البرنامج مرة أخرى الآن بعد أن أضفنا التعليمة return:

  1. python add_numbers.py
Output
(3, 4, 5)

نتلقى نفس الأرقام 3 و 4 و 5 كناتج كما تلقينا سابقًا باستخدام تعليمة print() في الدالة. هذه المرة يتم تقديمها كـ tuple لأن قائمة التعبيرات للتعليمة return تحتوي على على الأقل فاصلة واحدة.

الدوال تنتهي فورًا عند وصولها لتعليمة return، سواءً كانت تعيد قيمة أو لا.

return_loop.py
def loop_five():
    for x in range(0, 25):
        print(x)
        if x == 5:
            # توقف الدالة عند x == 5
            return
    print("This line will not execute.")

loop_five()

باستخدام تعليمة return داخل حلقة for ينهي الدالة، لذا لن يتم تشغيل السطر الذي يكون خارج الحلقة. إذا كنا قد استخدمنا تعليمة break بدلاً من ذلك، لكانت فقط الحلقة قد انتهت في تلك اللحظة، وسيتم تشغيل السطر الأخير في print().

العبارة return تخرج من الدالة، وقد تعيد قيمة عند استدعائها بمعامل.

استخدام main() كدالة

على الرغم من أنه في لغة Python يمكنك استدعاء الدالة في نهاية برنامجك وستعمل (كما فعلنا في الأمثلة أعلاه)، إلا أن العديد من لغات البرمجة (مثل C++ و Java) تتطلب وجود دالة main للتنفيذ. يمكن أن يجعل إضافة دالة main()، ورغم أنه ليس مطلوبًا، برامج Python الخاصة بنا منظمة بطريقة منطقية تضع أهم مكونات البرنامج في دالة واحدة. كما يمكن أن تجعل برامجنا أسهل لغير مبرمجي Python قراءتها.

سنبدأ بإضافة دالة main() إلى البرنامج hello.py أعلاه. سنحتفظ بدالة hello()، ثم نقوم بتعريف دالة main():

hello.py
def hello():
    print("Hello, World!")

def main():

داخل دالة main()، دعونا نضيف عبارة print() لتخبرنا بأننا في دالة main(). بالإضافة إلى ذلك، دعونا نستدعي دالة hello() داخل دالة main():

hello.py
def hello():
    print("Hello, World!")


def main():
    print("This is the main function")
    hello()

وأخيرًا، في نهاية البرنامج سنستدعي دالة main():

hello.py
def hello():
    print("Hello, World!")

def main():
    print("This is the main function.")
    hello()

main()

في هذه النقطة، يمكننا تشغيل برنامجنا:

  1. python hello.py

سنحصل على الناتج التالي:

Output
This is the main function. Hello, World!

لأننا استدعينا وظيفة hello() داخل main() وبعد ذلك استدعينا فقط main() لتشغيلها، تم طباعة النص Hello, World! مرة واحدة فقط، بعد السلسلة التي أخبرتنا أننا في الدالة الرئيسية.

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

في Python، '__main__' هو اسم النطاق الذي سيتم تنفيذ الشفرة على مستوى الأعلى فيه. عند تشغيل برنامج من المدخل القياسي، أو نص، أو من موجه تفاعلي، يتم تعيين قيمة __name__ الخاصة به إلى '__main__'.

بسبب ذلك، هناك اتفاقية لاستخدام البناء التالي:

if __name__ == '__main__':
    # الشفرة التي ستتم تنفيذها عندما يكون هذا البرنامج هو البرنامج الرئيسي هنا

هذا يسمح لملفات البرنامج أن تستخدم إما:

  • كالبرنامج الرئيسي وتشغيل ما يلي بعد عبارة if
  • كوحدة وعدم تشغيل ما يلي بعبارة if.

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

لنقوم بتوسيع برنامجنا names.py السابق، وإنشاء ملف جديد يسمى more_names.py. في هذا البرنامج، سنقوم بتعريف متغير عام وتعديل وظيفتنا الأصلية names() بحيث تكون التعليمات في وظيفتين منفصلتين.

الوظيفة الأولى، has_vowel() ستقوم بالتحقق مما إذا كانت السلسلة name تحتوي على حرف علة.

الوظيفة الثانية print_letters() ستقوم بطباعة كل حرف من سلسلة name.

more_names.py
# تعريف المتغير العام name للاستخدام في جميع الوظائف
name = str(input('Enter your name: '))


# تحديد وظيفة للتحقق مما إذا كان الاسم يحتوي على حرف علة
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Your name contains a vowel.')
    else:
        print('Your name does not contain a vowel.')


# الكرر على الأحرف في سلسلة الاسم
def print_letters():
    for letter in name:
        print(letter)

مع هذا الإعداد، دعونا نعرف الوظيفة main() التي ستحتوي على استدعاء لكل من وظيفتي has_vowel() و print_letters().

more_names.py
# تعريف المتغير العام name للاستخدام في جميع الوظائف
name = str(input('Enter your name: '))


# تحديد وظيفة للتحقق مما إذا كان الاسم يحتوي على حرف علة
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Your name contains a vowel.')
    else:
        print('Your name does not contain a vowel.')


# الكرر على الأحرف في سلسلة الاسم
def print_letters():
    for letter in name:
        print(letter)


# تحديد الوظيفة الرئيسية التي تستدعي الوظائف الأخرى
def main():
    has_vowel()
    print_letters()

أخيرًا، سنضيف بناء if __name__ == '__main__': في أسفل الملف. لأغراضنا، نظرًا لأننا وضعنا جميع الوظائف التي نود القيام بها في الوظيفة main()، سنقوم باستدعاء الوظيفة main() بعد هذا التعبير if.

more_names.py
# قم بتعريف متغير عالمي للاستخدام في جميع الوظائف
name = str(input('Enter your name: '))


# قم بتعريف وظيفة للتحقق مما إذا كان الاسم يحتوي على حرف علة
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Your name contains a vowel.')
    else:
        print('Your name does not contain a vowel.')


# قم بتكرار الأحرف في سلسلة الاسم
def print_letters():
    for letter in name:
        print(letter)


# قم بتعريف الطريقة الرئيسية التي تستدعي الوظائف الأخرى
def main():
    has_vowel()
    print_letters()


# قم بتنفيذ الوظيفة الرئيسية()
if __name__ == '__main__':
    main()

يمكننا الآن تشغيل البرنامج:

  1. python more_names.py

سيظهر البرنامج نفس الناتج الذي تظهره البرنامج names.py، ولكن هنا الكود أكثر تنظيمًا ويمكن استخدامه بطريقة متكاملة دون تعديل.

إذا لم تكن ترغب في تعريف وظيفة main()، يمكنك بدلاً من ذلك إنهاء البرنامج مثل هذا:

more_names.py
...
if __name__ == '__main__':
    has_vowel()
    print_letters()

استخدام main() كوظيفة وبيان if __name__ == '__main__': يمكن أن ينظم الكود بطريقة منطقية، مما يجعله أكثر قراءة وتنظيمًا.

الاستنتاج

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

لمعرفة المزيد حول كيفية جعل الشيفرة الخاصة بك أكثر تجزئة، يمكنك قراءة دليلنا حول كيفية كتابة الوحدات في Python 3.

Source:
https://www.digitalocean.com/community/tutorials/how-to-define-functions-in-python-3