دالة من غير ما تتعب نفسك بتسميتها
معظم الدوال في بايثون بتتعرّف باستخدام def، وبيكون ليها اسم، وبتعيش في ملف عشان نقدر نعيد استخدامها. أما lambda فهي بديل أصغر ومن غير اسم — بتنفع في الحالات القليلة اللي كتابة دالة كاملة فيها بتبقى رسميات زيادة عن اللزوم.
خلّينا نشوف الشكل جنب بعض:
دالتان، كلتاهما تقومان بالعمل ذاته تمامًا. النسخة المكتوبة بـ lambda تتّسع في سطر واحد فقط، لأن هذه هي مهمتها أصلًا: دالة سريعة تُستخدم لمرة واحدة في موقف عابر.
صيغة دالة lambda في بايثون
lambda <params>: <expression>
<params>هي نفس قائمة المعاملات التي تستخدمهاdef— تدعم القيم الافتراضية و*argsو**kwargs.<expression>تعبير واحد فقط، وقيمته هي ما تُرجعه الدالة.
أمثلة:
لا حاجة لاستخدام كلمة return، فقيمة التعبير تُعاد ضمنيًا بشكل تلقائي.
القيد الوحيد في دالة lambda
يمكن أن تحتوي دالة lambda على تعبير واحد فقط، ولا يمكن وضع جمل برمجية (statements) بداخلها:
لكن يمكنك استخدام التعبير الشرطي المختصر (ternary):
لو احتجت أكثر من تعبير واحد، فهذه إشارة واضحة إنك لازم تنتقل إلى def.
متى تستخدم دالة lambda فعلاً؟
إسناد دالة lambda إلى متغير يكون في الغالب أسوأ من تعريف دالة عادية باستخدام def:
هذا أسوأ فعليًا من def double(x): return x * 2 — نفس مستوى الوضوح، مع أن نسخة lambda تظهر في أثر التتبع (stack trace) باسم <lambda> غير المفيد إطلاقًا عند تصحيح الأخطاء.
الـ lambda تتألق في حالة واحدة فقط: حين تُمرَّر كوسيط مباشر لدوال من الرتبة الأعلى (higher-order functions).
ترتيب قائمة بايثون بمفتاح مخصص
المثال الكلاسيكي:
وسيط key في دالة sorted يتوقع منك تمرير دالة تستقبل عنصراً وتُرجع القيمة التي سيتم الترتيب على أساسها. هنا تبرز فائدة lambda في بايثون: سطر واحد مختصر يؤدي الغرض، بينما استخدام def كامل يبدو مبالغاً فيه لمهمة بهذه البساطة.
ويمكنك أيضاً الترتيب حسب أكثر من حقل عبر تمرير tuple:
min و max و filter و map
نفس الحكاية — كلّها تقبل دالة كوسيط اختياري:
مع map و filter، عادةً ما يكون استخدام list comprehension أوضح بكثير:
معظم مبرمجي بايثون يفضّلون الـ comprehensions على map و filter لهذا السبب بالذات. لكن تبقى lambda الخيار الطبيعي مع sorted و min و max، حيث لا يوجد اختصار مكافئ عبر الـ comprehensions.
دوال lambda مع وحدة operator
حين يكون كل ما تفعله الـ lambda هو "أحضِر مفتاحًا" أو "أحضِر خاصية"، فإن وحدة operator في بايثون توفّر بدائل أسرع وأوضح:
ليس مكسبًا ضخمًا، لكن في الكود الذي يستورد operator أصلًا، يبدو الأمر أكثر وضوحًا ومباشرة.
متى تعود إلى def؟
إذا انطبق أيٌّ مما يلي، فاكتب دالة بـ def:
- المنطق لا يتّسع بشكل مريح في تعبير واحد.
- تريد إعطاء الدالة اسمًا لأن الاسم سيجعل الكود أوضح.
- ستستخدم نفس المنطق في أكثر من موضع.
- الدالة تحتاج إلى docstring (وهذا ما لا تستطيع الـ lambda توفيره).
تذكّر: بايثون لا تُقيَّم بعدد الأسطر. الدالة المسمّاة من ثلاثة أسطر تقرأ أفضل بكثير من lambda من سطر واحد متى صار المنطق غير تافه.
التالي: الـ Decorators
الـ lambdas تتيح لك تمرير الدوال كقيم. أما الـ decorators فتأخذ الفكرة خطوة أبعد: فهي تسمح لك بتغليف أي دالة بسلوك قابل لإعادة الاستخدام — تسجيل، وقياس زمن، وتخزين مؤقت، ومصادقة — بمجرد وضع @ واحد في السطر الذي يسبقها. هذا موضوع الصفحة التالية.
الأسئلة الشائعة
ما هي دالة lambda في بايثون؟
lambda هي دالة قصيرة ومجهولة الاسم تكتبها في سطر واحد. مثلاً lambda x: x * 2 تكافئ تماماً def double(x): return x * 2، لكن بدون اسم. فائدتها الحقيقية تظهر حين تحتاج دالة صغيرة تمرّرها مباشرة كوسيط لدالة أخرى.
متى أستخدم lambda بدلاً من def؟
استخدم lambda للدوال التي تُستعمل لمرة واحدة وتحتوي تعبيراً واحداً فقط، مثل تلك التي تمرّرها لـ sorted أو max أو filter. أما إذا كان جسم الدالة أطول من تعبير واحد، أو إذا كنت ستعطيها اسماً، فاستخدم def. الدوال المسمّاة أوضح دائماً تقريباً.
ما هي قيود lambda؟
دالة lambda تقبل تعبيراً واحداً فقط، ولا تقبل جُمَل برمجية (statements). لا إسنادات، ولا كتل if كاملة (رغم أنه يمكنك استخدام الصيغة الثلاثية a if cond else b)، ولا منطق متعدد الأسطر. إذا وجدت نفسك تصارع هذه القيود، فحوّلها إلى def مباشرة.