لماذا enumerate؟
لو احتجت الفهرس (index) والقيمة معًا أثناء المرور على قائمة، الحل التقليدي
range(len(...)) مزعج. enumerate() تُرجع أزواج (index, value) مباشرة:
fruits = ["تفاح", "موز", "برتقال"]
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 تفاح
# 1 موز
# 2 برتقال
بداية مخصّصة بـ start
لعرض ترقيم بشري (1، 2، 3) بدل الفهرسة البرمجية من 0:
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
# 1. تفاح
# 2. موز
# 3. برتقال
دمج عدة قوائم بـ zip
zip() تمرّ على عدة قوائم بالتوازي، وتُنتج صفًّا (tuple) من كل واحدة في
كل خطوة:
names = ["سارة", "خالد", "نور"]
ages = [25, 30, 22]
for name, age in zip(names, ages):
print(f"{name}: {age} سنة")
# سارة: 25 سنة
# خالد: 30 سنة
# نور: 22 سنة
⚠️
zipتتوقّف تلقائيًا عند أقصر قائمة دون أي تحذير. إن أردت التأكّد أن كل القوائم بنفس الطول، مرّرstrict=True(متوفّرة من Python 3.10):zip(names, ages, strict=True) # يرمي ValueError لو اختلفت الأطوال
يمكن أيضًا تحويل النتيجة مباشرة لقاموس:
prices = dict(zip(["قلم", "كتاب"], [3, 15]))
print(prices) # {'قلم': 3, 'كتاب': 15}
تفكيك القيم (Unpacking)
بايثون تسمح بتفريغ قيم متسلسلة في متغيّرات متعدّدة دفعة واحدة:
point = (10, 20, 30)
x, y, z = point
print(x, y, z) # 10 20 30
عدد المتغيّرات يجب أن يطابق عدد القيم تمامًا، وإلا حصل ValueError.
تبديل قيمتين بدون متغيّر مؤقّت
a, b = 5, 10
a, b = b, a
print(a, b) # 10 5
التفكيك الممتد بـ *
النجمة * تجمع "كل الباقي" في قائمة، وتُستخدم مرّة واحدة فقط في نفس عملية
التفكيك:
numbers = [1, 2, 3, 4, 5]
first, *middle, last = numbers
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
💡 المتغيّر بعد
*يستقبل دائمًا قائمة، حتى لو كانت فارغة:a, *b = [1, 2]تجعلb = [].
جرّب بنفسك
📥 المدخلات (input) — قيمة في كل سطر
أخطاء شائعة
- استخدام
range(len(list))بدلenumerate— يعمل لكنه أطول وأقل وضوحًا. - افتراض أن
zipتملأ الفراغات عند اختلاف الأطوال — هي تتوقّف عند الأقصر. - محاولة استخدام أكثر من
*واحدة في نفس سطر التفكيك —SyntaxError. - عدد متغيّرات لا يطابق عدد القيم في تفكيك عادي (بدون
*) —ValueError.
🎯 التالي: الفهم الشامل (Comprehensions) — بناء قوائم وقواميس بسطر واحد.