مسار بايثون· الخطوة 17 من 19

دوال lambda في بايثون: دالة كاملة في سطر واحد

تعلّم كتابة دوال lambda في بايثون، والفرق بينها وبين def، وكيف تمرّرها إلى sorted و max لترتيب القوائم بذكاء، ومتى لا تستخدمها.

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

🎯 ماذا ستتعلم؟

بنهاية هذا الدرس ستكون قادرًا على:

  • كتابة دالة lambda في سطر واحد وفهم أجزائها.
  • المقارنة بين def و lambda ومعرفة متى تستخدم كلًا منهما.
  • كتابة lambda تأخذ معاملين أو أكثر.
  • تمرير lambda إلى sorted() و max() لترتيب قائمة بطريقتك.
  • تجنّب الحالات التي تجعل lambda صعبة القراءة.

🧰 ماذا تحتاج قبل أن تبدأ؟

يجب أن تعرف كيف تعرّف دالة بـ def وتستخدم return، وقد شرحنا ذلك في الدوال في بايثون. ويجب أن تكون مرتاحًا مع القوائم. ويفيدك درس تمرير عدة معاملات إلى الدوال. كل أكواد بايثون في هذا الدرس تعمل في مترجم بايثون في المتصفح، وهو محرر بايثون اون لاين لا يحتاج إلى أي تثبيت.

الفكرة ببساطة

عندما تريد أن تتذكّر شيئًا مهمًا وطويلًا، تكتبه في دفتر وتعطيه عنوانًا. لكن إذا أردت تذكير سريع مثل “اشترِ خبزًا”، تكتبه على ورقة لاصقة صغيرة وترميها بعد الاستخدام.

الدالة التي تكتبها بـ def هي صفحة الدفتر: لها اسم، وقد تكون طويلة، وتعود إليها مرات كثيرة. أما دالة lambda فهي الورقة اللاصقة: دالة صغيرة بلا اسم تكتبها في مكان استخدامها مباشرة. ولهذا تسمّى أيضًا الدالة المجهولة (anonymous function).

في برمجة بايثون تستخدم lambda عندما تكون الدالة قصيرة جدًا، وتحتاجها مرة واحدة أو مرتين فقط.

الخطوة 1: من def إلى lambda

لنبدأ بدالة عادية تضاعف رقمًا. هكذا كتبناها في درس الدوال:

def double(x):
    return x * 2

print(double(5))
print(double(21))
10
42

الآن الدالة نفسها بـ lambda. الشكل العام هو: الكلمة lambda، ثم المعاملات، ثم نقطتان، ثم القيمة التي تُرجعها.

double = lambda x: x * 2

print(double(5))
print(double(21))
10
42

اقرأ السطر الأول هكذا: “دالة تأخذ x وتُرجع x * 2”. لاحظ أنه لا توجد كلمة return؛ ما بعد النقطتين هو النتيجة تلقائيًا. وضعنا الدالة في المتغيّر double لنستدعيها بالاسم، تمامًا كأي دالة.

🚀 للمتقدمين: جرّب print(type(double)) في محرر بايثون اون لاين. سترى <class 'function'>، أي أن lambda تصنع دالة حقيقية من النوع نفسه الذي تصنعه def.

الخطوة 2: lambda بمعاملين

يمكن أن تأخذ lambda أكثر من معامل، وتفصل بينها بفاصلة كما في def. هنا دالة تجمع نقاط لاعب في جولتين:

add_points = lambda round1, round2: round1 + round2

print(add_points(30, 45))
print(add_points(12, 8))
75
20

ويمكنك أن تكتب أي عملية تريدها بعد النقطتين، ما دامت تعبيرًا واحدًا. هذه دالة تحسب مساحة المستطيل:

area = lambda width, height: width * height

print(area(4, 5))
print(area(10, 3))
20
30

الخطوة 3: القوة الحقيقية، تمرير lambda إلى دالة أخرى

حتى الآن كتبنا lambda ووضعناها في متغيّر. لكن هذا ليس استخدامها الأشهر. الاستخدام الأشهر هو تمريرها مباشرة إلى دالة أخرى تحتاج “قاعدة” صغيرة.

الدالة sorted() ترتّب قائمة. لكن كيف ترتّب قائمة من القوائم؟ مثلًا، عندك لاعبون وكل لاعب معه نقاطه:

players = [["سالم", 40], ["نورة", 95], ["خالد", 70]]

print(sorted(players))
[['خالد', 70], ['سالم', 40], ['نورة', 95]]

بايثون رتّبت اللاعبين بالاسم، لأن الاسم هو العنصر الأول في كل قائمة صغيرة. لكننا نريد الترتيب بالنقاط. هنا نعطي sorted() معاملًا اسمه key، وقيمته دالة تخبرها “على ماذا ترتّب”.

players = [["سالم", 40], ["نورة", 95], ["خالد", 70]]

by_score = sorted(players, key=lambda player: player[1])
print(by_score)
[['سالم', 40], ['خالد', 70], ['نورة', 95]]

الدالة lambda player: player[1] تأخذ لاعبًا وتُرجع نقاطه. sorted() تستدعي هذه الدالة على كل لاعب، ثم ترتّب حسب ما ترجعه. لو كتبنا هذه القاعدة بـ def لاحتجنا إلى ثلاثة أسطر واسم لن نستخدمه مرة أخرى.

هل تريد الأعلى أولًا؟ أضف reverse=True:

players = [["سالم", 40], ["نورة", 95], ["خالد", 70]]

top_first = sorted(players, key=lambda player: player[1], reverse=True)
print(top_first)
[['نورة', 95], ['خالد', 70], ['سالم', 40]]

الخطوة 4: max() و min() بالطريقة نفسها

الدالتان max() و min() تقبلان key أيضًا. من هو صاحب أعلى نقاط؟

players = [["سالم", 40], ["نورة", 95], ["خالد", 70]]

best = max(players, key=lambda player: player[1])
print("الأعلى:", best[0], "بـ", best[1], "نقطة")
الأعلى: نورة بـ 95 نقطة

ومثال آخر من عالم النصوص: أطول كلمة في قائمة. هنا القاعدة هي طول الكلمة:

words = ["قلم", "مدرسة", "كتاب", "حاسوب"]

longest = max(words, key=lambda word: len(word))
print(longest)
مدرسة

🚀 للمتقدمين: الدالتان map() و filter() تأخذان lambda أيضًا. map() تطبّق الدالة على كل عنصر، و filter() تُبقي العناصر التي ترجع لها الدالة True. جرّب في محرر بايثون: print(list(map(lambda x: x * 2, [1, 2, 3]))) يطبع [2, 4, 6]، و print(list(filter(lambda x: x > 1, [1, 2, 3]))) يطبع [2, 3]. لاحظ أننا نلفّ النتيجة بـ list() لنراها.

الخطوة 5: متى لا تستخدم lambda؟

lambda تقبل تعبيرًا واحدًا فقط بعد النقطتين. لا يمكنك أن تكتب فيها عدة أسطر، ولا حلقة، ولا if كاملًا مع else طويل. وعندما تصير القاعدة معقّدة، تصبح lambda صعبة القراءة.

القاعدة الذهبية: إذا احتجت إلى اسم لتشرح ما تفعله الدالة، أو إلى أكثر من سطر، استخدم def. وإذا كانت القاعدة واضحة من أول نظرة وتحتاجها مرة واحدة، فـ lambda مناسبة.

هذه الدالة يُفضّل أن تُكتب بـ def لأنها تفعل أكثر من شيء:

def grade_label(score):
    if score >= 90:
        return "ممتاز"
    if score >= 75:
        return "جيد جدًا"
    return "يحتاج مراجعة"

print(grade_label(93))
print(grade_label(60))
ممتاز
يحتاج مراجعة

⚠️ أخطاء شائعة

الأخطاء طبيعية جدًا في تعلم لغة بايثون، والمهم أن تفهم رسالة الخطأ. هذه ثلاثة أخطاء يقع فيها كثيرون مع lambda:

1. كتابة return داخل lambda

❌
double = lambda x: return x * 2
SyntaxError: invalid syntax

ما بعد النقطتين يُرجع تلقائيًا، فلا تكتب return:

# ✅
double = lambda x: x * 2
print(double(7))
14

2. نسيان الأقواس عند الاستدعاء

❌
square = lambda x: x * x
print(square)
<function <lambda> at 0x7f...>

الكود لا يتوقف، لكنه يطبع وصف الدالة بدل النتيجة. استدعِ الدالة بالأقواس وأعطها قيمة:

# ✅
square = lambda x: x * x
print(square(6))
36

3. تمرير key بدون lambda أو دالة

❌
players = [["سالم", 40], ["نورة", 95]]
print(sorted(players, key=1))
TypeError: 'int' object is not callable

المعامل key يريد دالة، لا رقمًا. أعطه lambda تُرجع العنصر الذي تريد الترتيب عليه:

# ✅
players = [["سالم", 40], ["نورة", 95]]
print(sorted(players, key=lambda player: player[1]))
[['سالم', 40], ['نورة', 95]]

🧪 جرّب بنفسك

افتح محرر بايثون اون لاين وجرّب هذه التحديات بالترتيب. كل تحدٍّ أصعب قليلًا من الذي قبله.

التحدي 1: تحويل الدرجات

عندك دالة بـ def تحوّل درجة من 100 إلى درجة من 10. أعد كتابتها بـ lambda واستدعها مرتين.

def to_ten(score):
    return score / 10

print(to_ten(85))
8.5
💡 اضغط لرؤية الحل
to_ten = lambda score: score / 10

print(to_ten(85))
print(to_ten(100))
8.5
10.0

التحدي 2: الأقرب إلى الصفر

عندك قائمة بدرجات الحرارة في مدن مختلفة. استخدم min() مع lambda لتجد الدرجة الأقرب إلى الصفر. تذكّر أن abs() تُرجع القيمة بدون إشارة سالبة.

temps = [12, -3, 7, -1, 25]
# اطبع الدرجة الأقرب إلى الصفر
print(temps)
[12, -3, 7, -1, 25]
💡 اضغط لرؤية الحل
temps = [12, -3, 7, -1, 25]

closest = min(temps, key=lambda t: abs(t))
print(closest)
-1

التحدي 3: ترتيب الفريق بالعمر

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

team = [["عمر", 15], ["هند", 12], ["يوسف", 17], ["مريم", 13]]
# رتّب بالعمر ثم اطبع الأسماء
print(team)
[['عمر', 15], ['هند', 12], ['يوسف', 17], ['مريم', 13]]
💡 اضغط لرؤية الحل
team = [["عمر", 15], ["هند", 12], ["يوسف", 17], ["مريم", 13]]

by_age = sorted(team, key=lambda member: member[1])
for member in by_age:
    print(member[0])
هند
مريم
عمر
يوسف

✅ اختبر نفسك

  1. ماذا يطبع print((lambda x: x + 3)(4))؟

    • أ) 7
    • ب) 4
    • ج) خطأ
  2. أي جملة صحيحة عن lambda؟

    • أ) يمكن أن تحتوي على عدة أسطر.
    • ب) تُرجع نتيجة التعبير بدون كلمة return.
    • ج) يجب أن يكون لها اسم دائمًا.
  3. صح أم خطأ: sorted(items, key=lambda x: x[0]) ترتّب القائمة حسب العنصر الأول في كل عنصر.

💡 اضغط لرؤية الإجابات
  1. أ) 7. كتبنا الدالة بين قوسين ثم استدعيناها مباشرة بالقيمة 4.
  2. ب). lambda تعبير واحد، وما بعد النقطتين هو النتيجة.
  3. صح. الدالة في key تُرجع العنصر الأول، و sorted() ترتّب حسبه.

📝 الخلاصة

  • lambda دالة صغيرة بلا اسم تُكتب في سطر واحد: lambda x: x * 2.
  • لا تكتب return فيها؛ ما بعد النقطتين هو النتيجة.
  • تقبل معاملًا واحدًا أو أكثر، لكنها تقبل تعبيرًا واحدًا فقط.
  • أشهر استخدام لها هو key في sorted() و max() و min().
  • إذا احتاجت الدالة إلى اسم أو عدة أسطر، فاستخدم def.

⏭️ الخطوة التالية

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