🔒

سجّل للوصول إلى الدروس

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

وصول مجاني لجميع دروس بايثون
حفظ تقدمك تلقائياً
بيئة تجربة بايثون التفاعلية
الدرس 13

أساسيات الدوال

الدوال هي قلب البرمجة - تعلم كيفية إنشاء كود منظم وقابل لإعادة الاستخدام

📚 الوحدة 4: الدوال ⏱️ 18 دقيقة قراءة

ما هي الدوال؟

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

Python تعريف واستدعاء الدوال
# تعريف دالة بسيطة
def تحية():
    """دالة تحية بسيطة."""
    print("مرحباً بالعالم!")

# استدعاء الدالة
تحية()  # المخرج: مرحباً بالعالم!
تحية()  # يمكن استدعاؤها عدة مرات

# دالة مع معامل
def تحية_شخص(الاسم):
    """تحية شخص معين."""
    print(f"مرحباً يا {الاسم}!")

تحية_شخص("أحمد")  # مرحباً يا أحمد!
تحية_شخص("سارة")   # مرحباً يا سارة!
🔍 تشريح الدالة
  • def - الكلمة المفتاحية لتعريف الدالة
  • اسم_الدالة - يتبع قواعد تسمية المتغيرات
  • (المعاملات) - المدخلات التي تقبلها الدالة
  • : - تبدأ جسم الدالة
  • """نص توثيقي""" - وصف اختياري للدالة
  • الكود المُزاح - جسم الدالة

المعاملات والوسيطات

Python الفرق بين المعاملات والوسيطات
# المعاملات vs الوسيطات:
# - المعاملات: المتغيرات في تعريف الدالة
# - الوسيطات: القيم المُمررة عند استدعاء الدالة

def جمع(أ, ب):  # أ و ب هي معاملات
    return أ + ب

الناتج = جمع(5, 3)  # 5 و 3 هي وسيطات
print(الناتج)  # 8

# معاملات متعددة
def تقديم(الاسم, العمر, المدينة):
    print(f"أنا {الاسم}، عمري {العمر} سنة، من {المدينة}")

تقديم("أحمد", 25, "القاهرة")

# الوسيطات الموضعية (الترتيب مهم)
تقديم("سارة", 30, "الرياض")     # الترتيب الصحيح
# تقديم(30, "سارة", "الرياض")  # خطأ! العمر سيكون 30، والاسم سيكون "سارة"

القيم المُرجعة

Python إرجاع القيم من الدوال
# إرجاع قيمة
def تربيع(ن):
    return ن ** 2

الناتج = تربيع(5)
print(الناتج)  # 25

# دالة بدون return تُرجع None
def تحية(الاسم):
    print(f"مرحباً يا {الاسم}")

الناتج = تحية("أحمد")
print(الناتج)  # None

# إرجاع قيم متعددة (كـ tuple)
def قسمة_وباقي(أ, ب):
    خارج_القسمة = أ // ب
    الباقي = أ % ب
    return خارج_القسمة, الباقي

ق, ب = قسمة_وباقي(17, 5)
print(f"17 ÷ 5 = {ق} والباقي {ب}")  # 17 ÷ 5 = 3 والباقي 2

# الإرجاع المبكر
def هل_بالغ(العمر):
    if العمر < 0:
        return None  # عمر غير صالح
    if العمر >= 18:
        return True
    return False

print(هل_بالغ(25))   # True
print(هل_بالغ(15))   # False
print(هل_بالغ(-5))   # None

المعاملات الافتراضية

Python القيم الافتراضية للمعاملات
# قيم افتراضية للمعاملات
def تحية(الاسم, رسالة_ترحيب="مرحباً"):
    print(f"{رسالة_ترحيب} يا {الاسم}!")

تحية("أحمد")              # مرحباً يا أحمد!
تحية("سارة", "أهلاً")     # أهلاً يا سارة!
تحية("محمد", "السلام عليكم")  # السلام عليكم يا محمد!

# معاملات افتراضية متعددة
def إنشاء_ملف_شخصي(الاسم, العمر=0, المدينة="غير محدد", نشط=True):
    return {
        "الاسم": الاسم,
        "العمر": العمر,
        "المدينة": المدينة,
        "نشط": نشط
    }

print(إنشاء_ملف_شخصي("أحمد"))
# {'الاسم': 'أحمد', 'العمر': 0, 'المدينة': 'غير محدد', 'نشط': True}

print(إنشاء_ملف_شخصي("سارة", 25, "القاهرة"))
# {'الاسم': 'سارة', 'العمر': 25, 'المدينة': 'القاهرة', 'نشط': True}
⚠️ تحذير: المعاملات الافتراضية المتغيرة

لا تستخدم كائنات متغيرة (قوائم، قواميس) كقيم افتراضية!

# خطأ - قيمة افتراضية متغيرة
def إضافة_عنصر(عنصر, القائمة=[]):
    القائمة.append(عنصر)
    return القائمة

print(إضافة_عنصر("أ"))  # ['أ']
print(إضافة_عنصر("ب"))  # ['أ', 'ب'] - غير متوقع!

# صحيح - استخدم None
def إضافة_عنصر(عنصر, القائمة=None):
    if القائمة is None:
        القائمة = []
    القائمة.append(عنصر)
    return القائمة

الوسيطات المُسماة

Python استخدام الوسيطات المُسماة
# الوسيطات المُسماة (الترتيب غير مهم)
def إنشاء_مستخدم(الاسم, العمر, البريد, نشط=True):
    return {
        "الاسم": الاسم,
        "العمر": العمر,
        "البريد": البريد,
        "نشط": نشط
    }

# جميعها موضعية
مستخدم1 = إنشاء_مستخدم("أحمد", 25, "ahmed@example.com")

# جميعها مُسماة
مستخدم2 = إنشاء_مستخدم(
    الاسم="سارة",
    العمر=30,
    البريد="sara@example.com",
    نشط=False
)

# مختلطة (الموضعية أولاً، ثم المُسماة)
مستخدم3 = إنشاء_مستخدم("محمد", 35, البريد="mohamed@example.com")

# الوسيطات المُسماة يمكن أن تكون بأي ترتيب
مستخدم4 = إنشاء_مستخدم(
    البريد="diana@example.com",
    الاسم="ديانا",
    العمر=28
)

print(مستخدم4)  # الترتيب لا يهم للوسيطات المُسماة

النصوص التوثيقية (Docstrings)

Python توثيق الدوال
def حساب_المساحة(الطول, العرض):
    """
    حساب مساحة المستطيل.

    المعاملات:
        الطول (float): طول المستطيل.
        العرض (float): عرض المستطيل.

    الإرجاع:
        float: مساحة المستطيل.

    مثال:
        >>> حساب_المساحة(5, 3)
        15
    """
    return الطول * العرض

# الوصول للنص التوثيقي
print(حساب_المساحة.__doc__)

# استخدام help()
help(حساب_المساحة)

# نص توثيقي من سطر واحد للدوال البسيطة
def تربيع(ن):
    """إرجاع مربع ن."""
    return ن ** 2

النطاق والمتغيرات

Python النطاق المحلي والعام
# النطاق المحلي vs العام
متغير_عام = "أنا عام"

def دالتي():
    متغير_محلي = "أنا محلي"
    print(متغير_عام)   # يمكن قراءة العام
    print(متغير_محلي)  # يمكن قراءة المحلي

دالتي()
print(متغير_عام)      # يعمل
# print(متغير_محلي)   # NameError - غير متاح

# تعديل المتغيرات العامة
العداد = 0

def زيادة():
    global العداد  # إعلان نية تعديل المتغير العام
    العداد += 1

زيادة()
زيادة()
print(العداد)  # 2

# طريقة أفضل: تجنب الحالة العامة
def زيادة_قيمة(القيمة):
    return القيمة + 1

العداد = 0
العداد = زيادة_قيمة(العداد)
العداد = زيادة_قيمة(العداد)
print(العداد)  # 2

# إخفاء المتغير
س = 10

def دالة():
    س = 20  # ينشئ متغير محلي جديد، لا يعدل العام
    print(f"داخل: {س}")

دالة()           # داخل: 20
print(f"خارج: {س}")  # خارج: 10

الدوال المُدمجة الشائعة

Python دوال بايثون المُدمجة
# تحويل الأنواع
int("42")          # 42
float("3.14")      # 3.14
str(100)           # "100"
bool(1)            # True
list("أبج")        # ['أ', 'ب', 'ج']

# دوال رياضية
abs(-5)            # 5
round(3.7)         # 4
round(3.14159, 2)  # 3.14
pow(2, 3)          # 8
min(1, 2, 3)       # 1
max(1, 2, 3)       # 3
sum([1, 2, 3])     # 6

# دوال التسلسلات
len([1, 2, 3])     # 3
sorted([3, 1, 2])  # [1, 2, 3]
reversed([1, 2])   # مُكرر
list(reversed([1, 2, 3]))  # [3, 2, 1]

# مساعدات التكرار
range(5)           # 0, 1, 2, 3, 4
enumerate(['أ', 'ب'])  # (0, 'أ'), (1, 'ب')
zip([1, 2], ['أ', 'ب'])  # (1, 'أ'), (2, 'ب')

# الإدخال/الإخراج
print("مرحباً")     # إخراج
# input("الاسم: ")  # الحصول على إدخال المستخدم

# فحص الأنواع
type(42)           # 
isinstance(42, int)  # True

# معلومات الكائن
id(42)             # عنوان الذاكرة
dir([])            # قائمة الخصائص/الدوال
help(print)        # التوثيق

🎯 تحدي: محول درجات الحرارة

أنشئ دوالاً للتحويل بين مقاييس درجات الحرارة:

  1. مئوي_إلى_فهرنهايت(م)
  2. فهرنهايت_إلى_مئوي(ف)
  3. مئوي_إلى_كلفن(م)
  4. دالة رئيسية تحويل_حرارة(القيمة, من_مقياس, إلى_مقياس)
💡 عرض الحل
def مئوي_إلى_فهرنهايت(م):
    """تحويل مئوي إلى فهرنهايت."""
    return (م * 9/5) + 32

def فهرنهايت_إلى_مئوي(ف):
    """تحويل فهرنهايت إلى مئوي."""
    return (ف - 32) * 5/9

def مئوي_إلى_كلفن(م):
    """تحويل مئوي إلى كلفن."""
    return م + 273.15

def كلفن_إلى_مئوي(ك):
    """تحويل كلفن إلى مئوي."""
    return ك - 273.15

def تحويل_حرارة(القيمة, من_مقياس, إلى_مقياس):
    """
    تحويل درجة الحرارة بين المقاييس.

    المقاييس: 'م' (مئوي), 'ف' (فهرنهايت), 'ك' (كلفن)
    """
    من_مقياس = من_مقياس.upper()
    إلى_مقياس = إلى_مقياس.upper()

    # تحويل إلى مئوي أولاً
    if من_مقياس == 'ف':
        مئوي = فهرنهايت_إلى_مئوي(القيمة)
    elif من_مقياس == 'ك':
        مئوي = كلفن_إلى_مئوي(القيمة)
    else:
        مئوي = القيمة

    # تحويل من مئوي إلى الهدف
    if إلى_مقياس == 'ف':
        return مئوي_إلى_فهرنهايت(مئوي)
    elif إلى_مقياس == 'ك':
        return مئوي_إلى_كلفن(مئوي)
    return مئوي

# اختبار
print(f"0°م = {تحويل_حرارة(0, 'م', 'ف'):.1f}°ف")
print(f"100°م = {تحويل_حرارة(100, 'م', 'ك'):.1f}ك")
print(f"32°ف = {تحويل_حرارة(32, 'ف', 'م'):.1f}°م")

🎯 تحدي: دوال الآلة الحاسبة

أنشئ آلة حاسبة بسيطة بدوال لـ:

  • العمليات الأساسية: جمع، طرح، ضرب، قسمة
  • دالة حساب(أ, ب, العملية)
  • التعامل مع القسمة على صفر بشكل سليم
💡 عرض الحل
def جمع(أ, ب):
    """جمع عددين."""
    return أ + ب

def طرح(أ, ب):
    """طرح ب من أ."""
    return أ - ب

def ضرب(أ, ب):
    """ضرب عددين."""
    return أ * ب

def قسمة(أ, ب):
    """قسمة أ على ب. يُرجع None إذا كان ب صفراً."""
    if ب == 0:
        return None
    return أ / ب

def حساب(أ, ب, العملية):
    """
    تنفيذ العملية الحسابية.

    العمليات: 'جمع', 'طرح', 'ضرب', 'قسمة'
    أيضاً يقبل: '+', '-', '*', '/'
    """
    العمليات = {
        'جمع': جمع, '+': جمع,
        'طرح': طرح, '-': طرح,
        'ضرب': ضرب, '*': ضرب,
        'قسمة': قسمة, '/': قسمة
    }

    دالة_العملية = العمليات.get(العملية)
    if دالة_العملية is None:
        return f"عملية غير معروفة: {العملية}"

    الناتج = دالة_العملية(أ, ب)
    if الناتج is None:
        return "خطأ: القسمة على صفر"
    return الناتج

# اختبار
print(حساب(10, 5, 'جمع'))      # 15
print(حساب(10, 5, '-'))        # 5
print(حساب(10, 5, 'ضرب'))      # 50
print(حساب(10, 0, 'قسمة'))     # رسالة خطأ

📝 ملخص الدرس

  • الدوال تُعرَّف بـ def اسم_الدالة(المعاملات):
  • استخدم return لإرسال القيم للمُستدعي
  • المعاملات الافتراضية توفر قيم احتياطية
  • الوسيطات المُسماة تسمح بتمرير المعاملات بالاسم
  • النصوص التوثيقية توثق ما تفعله الدوال
  • المتغيرات داخل الدوال محلية بشكل افتراضي
  • تجنب الوسيطات الافتراضية المتغيرة (استخدم None بدلاً منها)

في الدرس التالي، سنستكشف مفاهيم الدوال المتقدمة مثل *args و **kwargs ودوال lambda!