تكرار السؤال: …
الإجابة المختصرة
الـ closure دالة داخلية تحتفظ بإشارة إلى متغيرات النطاق المحيط، لكن قيمة المتغير تُقرأ وقت الاستدعاء لا وقت الإنشاء، لذلك ترى كل الدوال المنشأة في حلقة آخر قيمة للمتغير.
الشرح
تشير الـ closure إلى المتغير نفسه (cell) وليس إلى نسخة من قيمته. عند إنشاء lambdas داخل حلقة وتشغيلها لاحقًا، تقرأ جميعها القيمة النهائية لمتغير الحلقة. الحلول: تثبيت القيمة كمعامل افتراضي (lambda n=n: n)، أو استخدام functools.partial، أو دالة factory تنشئ نطاقًا جديدًا لكل قيمة. ولتعديل متغير من النطاق المحيط داخل الدالة الداخلية استخدم nonlocal.
مثال بالكود
callbacks = [lambda: n for n in range(3)]
print([f() for f in callbacks]) # [2, 2, 2]
callbacks = [lambda n=n: n for n in range(3)]
print([f() for f in callbacks]) # [0, 1, 2]
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return incأخطاء شائعة
- إنشاء callbacks داخل حلقة وتوقع أن كلًا منها يحمل قيمته الخاصة.
- نسيان nonlocal عند تعديل متغير محيط مما يرمي UnboundLocalError.