3.3الدوال المتقدمة : المزخرفات (decorators)، المولدات (generators)، لامدا (lambdas)، map/filter
الأساسي في 30 ثانية
- لامدا (lambda) = دالة مجهولة هالكة من سطر : key=lambda t: t[1] للترتيب — وdef متى تسمت أو أعيد استعمالها.
- المزخرف (decorator) يغلف دون مساس : @chrono يضيف قياسا أو سجلا أو ضبطا باستقبال الدالة وإرجاع غلاف — مع functools.wraps.
- المولد (generator) ينتج عند الطلب : yield يعالج ملفا ضخما بذاكرة ثابتة — القوائم للصغير، والمولدات للكبير.
حالة مصغرة متسلسلة — نبيل يمر إلى البايثوني
نبيل، محلل بيانات مبتدئ في الجزائر، يرتب مبيعاته بدوال من ثلاثة أسطر لاستعمال واحد ويحمل تصديرا بعدة غيغابايت في قائمة — فيئن حاسوبه. يرتب في سطر (key=lambda v: v["montant"])، ويقارن map/filter بالاستيعابات، ويقرأ التصدير سطرا بسطر عبر مولد (generator) بـ yield، ويقيس معالجاته بمزخرف (decorator) @chrono بـ functools.wraps. البيانات نفسها، وكود قصير وحاسوب مرتاح.
هذه الحالة نفسها تعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة.
1. لامدا (lambda)، map/filter : العدة الصغيرة
لامدا (lambda) دالة مجهولة من سطر، للاستعمال الهالك كوسيط : sorted(ventes, key=lambda v: v["montant"]) يرتب بمعيار دون تسمية دالة. map تطبق دالة على كل عنصر، وfilter لا تبقي إلا ما يحقق شرطا — لكن الاستيعاب ([f(x) for x in xs if ok(x)]) غالبا أوضح في بايثون.
قاعدة نبيل : لامدا (lambda) للهالك القصير، وdef متى تسمى أو أعيد استعمالها أو تجاوزت سطرا. لامدا من خمسة أسطر هي def متنكرة : سمها، ووثقها، واختبرها. هذه العدة تُصادَف في كل مكان (مفاتيح الترتيب، النداءات) — معرفتها تعني قراءة كود الآخرين بطلاقة.
2. المزخرفات (decorators) والمولدات (generators) : التغليف والتخفيف
المزخرف (decorator) يغني دالة دون تعديل كودها : يستقبلها، ويرجع غلافا يضيف قياسا أو سجلا أو تخزينا أو ضبطا، عبر الصيغة @decorateur. ودائما مع functools.wraps لحفظ الاسم وسلسلة التوثيق. يكتب نبيل @chrono التي تعرض زمن التنفيذ — ويتعرف الآلية خلف @app.route أو @pytest.fixture.
المولد (generator) (دالة بـ yield) ينتج قيمه واحدة واحدة، عند الطلب : معلق عند كل yield، ومستأنَف عند النداء التالي. تصدير بعدة غيغابايت يُقرأ سطرا بسطر بذاكرة ثابتة بدل تفجير RAM. القوائم للصغير المعاد استعماله، والمولدات للكبير أو اللانهائي : إنه الخيار القابل للتوسع.
القائمة التي أكلت RAM
تدفق كبير، yield صغير : الذاكرة تشكرك.
🔎 مثال ملموس — التوقيت دون مساس + القراءة دون تحميل
يقيس نبيل معالجته ويقرأ تصديرا ضخما سطرا بسطر.
import time
import functools
def chrono(f):
@functools.wraps(f)
def enveloppe(*args, **kwargs):
debut = time.perf_counter()
resultat = f(*args, **kwargs)
duree = time.perf_counter() - debut
print(f"{f.__name__}: {duree:.2f}s")
return resultat
return enveloppe
def lignes(fichier):
with open(fichier, encoding="utf-8") as f:
for ligne in f:
yield ligne.strip()
القراءة : @chrono يقيس دون مساس بالمتن ؛ وyield لا تحمل سوى سطر كل مرة.
الدرس : wraps تحفظ اسم الدالة المزخرفة وتوثيقها.
مفردات القسم
- لامدا (lambda)
- دالة مجهولة من سطر (lambda x: x * 2)، نافعة لمعالجة قصيرة تُمرَّر كوسيط.
مثال بسيط: عبارة key=lambda v: v["montant"] لترتيب نبيل.
ما ليس كذلك: دالة مسماة معاد استعمالها وموثقة.
رد فعل: لامدا هالكة، وdef متى تسمت.
- map / filter
- تطبق map دالة على كل عنصر ؛ ولا تبقي filter إلا ما يحقق شرطا.
مثال بسيط: عبارة map(lambda x: x ** 2, montants) ثم filter الزوجيات عند نبيل.
ما ليس كذلك: استيعاب غالبا أوضح.
رد فعل: قارن بالاستيعاب قبل الاختيار.
- المولد (generator)
- دالة بـ yield تنتج قيمها واحدة واحدة عند الطلب : ذاكرة دنيا، مثالية للتدفقات الكبيرة.
مثال بسيط: سطورة التصدير مقروءة واحدا واحدا عند نبيل.
ما ليس كذلك: قائمة عملاقة محملة دفعة واحدة في RAM.
رد فعل: yield متى كان كبيرا أو لانهائيا.
- yield
- ترجع قيمة مع تعليق الدالة، وتُستأنَف عند النداء التالي : قلب المولدات (generators).
مثال بسيط: كل yield ligne.strip() لتصدير نبيل.
ما ليس كذلك: return تنهي الدالة.
رد فعل: كرر دون تحميل الكل.
- المزخرف (decorator)
- دالة تغلف أخرى لإضافة سلوك (chrono، سجل، ضبط)، عبر @decorateur و functools.wraps.
مثال بسيط: عبارة @chrono لنبيل على معالجاته.
ما ليس كذلك: نسخ كود القياس في كل دالة.
رد فعل: جمع المستعرض في مزخرف.
في التطبيق — كتابة بايثون بايثوني
- رتبوا ثنائيات حسب العنصر الثاني بـ sorted(..., key=lambda t: t[1]) على مبيعات نبيل.
- حولوا بـ map(lambda x: x ** 2, nombres) ورشحوا بـ filter(lambda x: x % 2 == 0, nombres)، ثم قارنوا بالاستيعابات.
- اكتبوا مولدا (generator) بـ yield ينتج الزوجيات إلى اللانهاية ؛ واستهلكوا منه 10 بـ break.
- أنشئوا مزخرفا (decorator) @chrono بـ functools.wraps يعرض زمن التنفيذ، ثم طبقوه.
نص جاهز للقول — عرض كوده البايثوني (30 ثانية)
« ترتيب بلامدا (lambda) هالكة على المبلغ، ومولد (generator) بـ yield للتصدير الضخم بذاكرة ثابتة، ومزخرف (decorator) chrono مع wraps للقياس دون مساس. وmap وfilter مقارَنة بالاستيعابات حالة بحالة. »
يُقال في المراجعة ؛ ويُعرَض @chrono و yield.
نموذج نسخ-لصق — مزخرف (decorator) chrono + مولد (generator)
import time
import functools
def chrono(f):
@functools.wraps(f)
def enveloppe(*args, **kwargs):
debut = time.perf_counter()
resultat = f(*args, **kwargs)
print(f"{f.__name__}: {time.perf_counter() - debut:.2f}s")
return resultat
return enveloppe
@chrono
def total(montants):
return sum(montants)
ventes_triees = sorted([{"v": "Alger", "m": 9}, {"v": "Oran", "m": 4}], key=lambda v: v["m"])
مستقل
يكفي @chrono + ترتيب بلامدا لتتبع أداء التقارير.
مقاولة صغيرة في الجزائر
يقرأ نبيل تصدير الصناديق بعدة غيغابايت بمولد (generator) دون تغيير الحاسوب.
فريق منتج
فرض wraps في كل مزخرف (decorator) لإبقاء الأسماء والتوثيقات قابلة للاستغلال.
مبتدئ
هذا الأسبوع : ترتيب بلامدا ومولد زوجيات إلى اللانهاية.
✓ ممارسات جيدة
- حصر لامدا (lambda) في الهالك القصير ؛ وتسمية def متى أعيد الاستعمال.
- إضافة functools.wraps في كل مزخرف (decorator) (الاسم والتوثيق محفوظان).
- المرور إلى yield متى كانت البيانات كبيرة أو لانهائية.
✗ أخطاء شائعة
- كتابة لامدا (lambda) من خمسة أسطر غير مقروءة بدل def.
- نسيان wraps (الاسم مفقود، والاستبطان مكسور).
- تحميل ملف عملاق في قائمة بدل مولد (generator).
النقاط الأساسية
- لامدا (lambda) = دالة مجهولة من سطر واحد، كوسيط (key في sorted…) ؛ وغير ذلك def.
- المزخرف (decorator) = غلاف دون مساس (@ + wraps) : قياس وسجل وضبط مجمعة.
- المولد (generator) (yield) = إنتاج عند الطلب، ذاكرة ثابتة : خيار الكبير.
- هذه الأدوات في كل مكان في أطر العمل : إدارتها تعني قراءة كود المحترفين.
تحدي 48 ساعة — طبّق غدا
اكتبوا مزخرفا (decorator) واحدا @chrono مع wraps ومولدا (generator) واحدا بـ yield على بياناتكم.
- أرتب بلامدا دون تسمية دالة هالكة.
- مزخرفي (decorator) يحفظ الاسم والتوثيق عبر wraps.
- تدفقي الكبير يمر بمولد (generator)، لا بقائمة.
أسئلة شائعة
متى نفضل مولدا (generator) على قائمة ؟
عندما تكون البيانات ضخمة أو لانهائية : تحمل القائمة كل شيء في الذاكرة، وينتج المولد (generator) قيمة واحدة كل مرة. لقراءة ملف بعدة غيغابايت سطرا بسطر، المولد لا غنى عنه ؛ ولبضعة عناصر معاد استعمالها، تكفي قائمة.
المزخرف (decorator)، ما فائدته عمليا ؟
إضافة سلوك متكرر (chrono، سجل، ضبط، تخزين) إلى عدة دوال دون نسخه في كل مكان. تستعملون منها أصلا : @app.route، و@staticmethod، و@pytest.fixture — الآلية نفسها، والأناقة نفسها.
لماذا functools.wraps في مزخرف (decorator) ؟