دوال لامبدا (Lambda): كتابة الدوال السريعة والمجهولة في سطر واحد


دوال لامبدا (Lambda): كتابة الدوال السريعة والمجهولة في سطر واحد

ماذا سنتعلم اليوم؟ سنتعمق في فهم دوال لامبدا (Lambda) في بايثون، وكيفية استخدامها لكتابة دوال صغيرة، سريعة، ومجهولة الهوية في سطر واحد لتنفيذ مهام محددة بكفاءة.

الخطوة 1: فهم الأساسيات - Lambda مقابل الدوال العادية

دوال لامبدا هي دوال صغيرة، مجهولة (أي لا تحمل اسماً)، ومحدودة بسطر واحد من التعبير. غالبًا ما تستخدم للمهام التي تتطلب دالة بسيطة لمرة واحدة. لنقارنها بدالة عادية:

# دالة عادية لجمع عددين
def add_normal(a, b):
    return a + b

print(f"الجمع باستخدام الدالة العادية: {add_normal(5, 3)}") # الناتج: 8

# دالة لامبدا مكافئة لجمع عددين
add_lambda = lambda a, b: a + b

print(f"الجمع باستخدام دالة لامبدا: {add_lambda(5, 3)}") # الناتج: 8
ملاحظة تقنية: الفرق الجوهري هو أن lambda لا تتطلب كلمة مفتاحية return بشكل صريح، فالتعبير بعد النقطتين : هو القيمة المرجعة. كما أنها لا تدعم عبارات متعددة الأسطر أو تعليقات داخل تعريفها.

الخطوة 2: استخدام Lambda مع دوال الترتيب العالي (Higher-Order Functions)

تتألق دوال لامبدا حقًا عند استخدامها مع دوال الترتيب العالي مثل map()، filter()، و sorted() التي تقبل دالة كوسيط.

# قائمة أرقام
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# استخدام map مع lambda لتربيع كل رقم
# map تطبق الدالة (lambda x: x**2) على كل عنصر في القائمة (numbers)
squared_numbers = list(map(lambda x: x**2, numbers))
print(f"الأرقام مربعة: {squared_numbers}") # الناتج: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# استخدام filter مع lambda لتصفية الأرقام الزوجية فقط
# filter تحتفظ بالعناصر التي تعيد الدالة (lambda x: x % 2 == 0) قيمة True لها
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"الأرقام الزوجية: {even_numbers}") # الناتج: [2, 4, 6, 8, 10]

# استخدام sorted مع lambda لفرز قائمة من القواميس بناءً على قيمة معينة
students = [
    {'name': 'أحمد', 'grade': 85},
    {'name': 'سارة', 'grade': 92},
    {'name': 'علي', 'grade': 78}
]
# نفرز الطلاب حسب الدرجة تنازلياً
sorted_students = sorted(students, key=lambda student: student['grade'], reverse=True)
print(f"الطلاب مرتبون حسب الدرجة (تنازلياً): {sorted_students}")
# الناتج: [{'name': 'سارة', 'grade': 92}, {'name': 'أحمد', 'grade': 85}, {'name': 'علي', 'grade': 78}]
ملاحظة تقنية: map() و filter() ترجعان كائنات map و filter على التوالي. يجب تحويلها إلى قائمة (list()) لرؤية النتائج مباشرة.

الخطوة 3: Lambda كوسيط لدوال أخرى (Callbacks)

يمكن تمرير دوال لامبدا كوسيط (callback) لدوال مخصصة تقوم بتنفيذها في وقت لاحق. هذا شائع في البرمجة الموجهة بالأحداث أو عند الحاجة لتخصيص سلوك دالة معينة.

# دالة تأخذ دالة أخرى كوسيط وتطبقها
def apply_operation(x, y, operation):
    return operation(x, y)

# استخدام lambda كـ "عملية" لتطبيق الجمع
result_add = apply_operation(10, 5, lambda a, b: a + b)
print(f"نتيجة الجمع باستخدام lambda كوسيط: {result_add}") # الناتج: 15

# استخدام lambda كـ "عملية" لتطبيق الضرب
result_multiply = apply_operation(10, 5, lambda a, b: a * b)
print(f"نتيجة الضرب باستخدام lambda كوسيط: {result_multiply}") # الناتج: 50

الكود النهائي الكامل

إليك السكربت كاملاً الذي يجمع كل الأمثلة التي ناقشناها:

# ---------------------------------------------------
# الخطوة 1: فهم الأساسيات - Lambda مقابل الدوال العادية
# ---------------------------------------------------

# دالة عادية لجمع عددين
def add_normal(a, b):
    return a + b

print(f"الجمع باستخدام الدالة العادية: {add_normal(5, 3)}")

# دالة لامبدا مكافئة لجمع عددين
add_lambda = lambda a, b: a + b
print(f"الجمع باستخدام دالة لامبدا: {add_lambda(5, 3)}")

print("-" * 30) # خط فاصل للتنسيق

# ---------------------------------------------------
# الخطوة 2: استخدام Lambda مع دوال الترتيب العالي
# ---------------------------------------------------

# قائمة أرقام
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# استخدام map مع lambda لتربيع كل رقم
squared_numbers = list(map(lambda x: x**2, numbers))
print(f"الأرقام مربعة: {squared_numbers}")

# استخدام filter مع lambda لتصفية الأرقام الزوجية فقط
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"الأرقام الزوجية: {even_numbers}")

# قائمة من القواميس لفرزها
students = [
    {'name': 'أحمد', 'grade': 85},
    {'name': 'سارة', 'grade': 92},
    {'name': 'علي', 'grade': 78}
]
# نفرز الطلاب حسب الدرجة تنازلياً
sorted_students = sorted(students, key=lambda student: student['grade'], reverse=True)
print(f"الطلاب مرتبون حسب الدرجة (تنازلياً): {sorted_students}")

print("-" * 30) # خط فاصل للتنسيق

# ---------------------------------------------------
# الخطوة 3: Lambda كوسيط لدوال أخرى (Callbacks)
# ---------------------------------------------------

# دالة تأخذ دالة أخرى كوسيط وتطبقها
def apply_operation(x, y, operation):
    return operation(x, y)

# استخدام lambda كـ "عملية" لتطبيق الجمع
result_add = apply_operation(10, 5, lambda a, b: a + b)
print(f"نتيجة الجمع باستخدام lambda كوسيط: {result_add}")

# استخدام lambda كـ "عملية" لتطبيق الضرب
result_multiply = apply_operation(10, 5, lambda a, b: a * b)
print(f"نتيجة الضرب باستخدام lambda كوسيط: {result_multiply}")

النتيجة المتوقعة

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

الجمع باستخدام الدالة العادية: 8
الجمع باستخدام دالة لامبدا: 8
------------------------------
الأرقام مربعة: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
الأرقام الزوجية: [2, 4, 6, 8, 10]
الطلاب مرتبون حسب الدرجة (تنازلياً): [{'name': 'سارة', 'grade': 92}, {'name': 'أحمد', 'grade': 85}, {'name': 'علي', 'grade': 78}]
------------------------------
نتيجة الجمع باستخدام lambda كوسيط: 15
نتيجة الضرب باستخدام lambda كوسيط: 50