إذا كنت تمر على عناصر List في بايثون وتحتاج إلى معرفة رقم كل عنصر وقيمته في الوقت نفسه، فدالة enumerate() هي واحدة من أوضح الأدوات لهذا الغرض.
بدل كتابة range(len(list)) ثم استخدام رقم الفهرس للوصول إلى العنصر، تستطيع enumerate() إعطاءك عدادًا والعنصر مباشرة داخل حلقة for.
في هذا الدرس من بايثون العرب سنشرح كيف تعمل enumerate()، والفرق بينها وبين range() وlen()، وكيف تستخدم start بطريقة صحيحة دون الخلط بين رقم العرض والفهرس الحقيقي للقائمة.
وسنوضح أيضًا متى لا تحتاج إلى enumerate() أصلًا، ومتى تكون حلقة for العادية أو range() أنسب، حتى تختار الأسلوب الصحيح بدل استخدام الدالة في كل حالة.
{getToc} $title={محتوى المقال}
{alertInfo} إذا كنت تحتاج إلى قيمة العنصر فقط فاستخدمfor item in list. أما إذا كنت تحتاج إلى رقم مع العنصر أثناء المرور، فغالبًاenumerate()هي الأنسب.
قبل المتابعة، يفيد أن تكون مرتاحًا مع القوائم Lists في بايثون و الحلقات Loops في بايثون.
ما هي دالة enumerate في بايثون؟
دالة enumerate() هي دالة مدمجة في بايثون تستقبل شيئًا قابلًا للتكرار مثل List، وتعيد كائن enumerate. وعند المرور عليه، تحصل في كل مرة على زوج يحتوي على عداد وقيمة العنصر.
names = ["Ahmed", "Sara", "Omar"]
print(list(enumerate(names)))
الناتج:
[(0, 'Ahmed'), (1, 'Sara'), (2, 'Omar')]
لاحظ أن كل عنصر في النتيجة عبارة عن زوج: الرقم أولًا، ثم القيمة. والقيمة الافتراضية لبداية العداد هي 0.
استخدام enumerate داخل for loop
الاستخدام الأكثر شيوعًا هو تفكيك الرقم والعنصر مباشرة داخل حلقة for:
names = ["Ahmed", "Sara", "Omar"]
for index, name in enumerate(names):
print(index, name)
الناتج:
0 Ahmed
1 Sara
2 Omar
هنا المتغير index يساوي 0 ثم 1 ثم 2، بينما المتغير name يحمل العنصر المقابل في القائمة.
لماذا enumerate أوضح من range(len())؟
يمكنك الحصول على النتيجة نفسها باستخدام range() وlen():
names = ["Ahmed", "Sara", "Omar"]
for i in range(len(names)):
print(i, names[i])
هذا الكود صحيح، لكنك تحصل أولًا على الرقم ثم تستخدمه للوصول إلى العنصر عبر names[i]. إذا كان هدفك فقط الحصول على الرقم والعنصر أثناء المرور، فإن enumerate() تعبر عن الفكرة مباشرة.
| الحالة | الأسلوب الأنسب | لماذا؟ |
|---|---|---|
| أحتاج إلى قيمة العنصر فقط | for item in items |
الأبسط ولا تحتاج إلى رقم |
| أحتاج إلى الرقم والعنصر معًا | enumerate(items) |
تعطيك الاثنين مباشرة |
| أحتاج إلى تسلسل أرقام أو حسابات على الفهارس نفسها | range(...) |
تتعامل مباشرة مع الأرقام |
تغيير بداية العداد باستخدام start
يمكنك تغيير الرقم الذي يبدأ منه عداد enumerate() باستخدام المعامل start. وهذا مفيد عند عرض قائمة مرقمة للمستخدم.
names = ["Ahmed", "Sara", "Omar"]
for number, name in enumerate(names, start=1):
print(number, name)
الناتج:
1 Ahmed
2 Sara
3 Omar
{alertWarning} مهم:start=1لا يغيّر الفهرس الحقيقي لعناصر القائمة. هو يغيّر عدادenumerate()فقط. فالعنصر"Ahmed"ما يزال في الفهرس الحقيقي0.
الفرق بين index الحقيقي ورقم العرض
هذا الفرق مهم جدًا للمبتدئ. في المثال التالي، نعرض رقمًا يبدأ من 1 للمستخدم، لكننا نطبع أيضًا الفهرس الحقيقي للقائمة:
names = ["Ahmed", "Sara", "Omar"]
for index, name in enumerate(names):
display_number = index + 1
print(f"رقم العرض: {display_number} - index: {index} - {name}")
بهذه الطريقة يبقى معنى index دقيقًا، ونستخدم متغيرًا آخر عندما نريد ترقيمًا مناسبًا للعرض.
مثال عملي: عرض قائمة مهام مرقمة
tasks = [
"Learn Python",
"Practice loops",
"Build a small project"
]
for number, task in enumerate(tasks, start=1):
print(f"{number}. {task}")
الناتج:
1. Learn Python
2. Practice loops
3. Build a small project
هنا تسمية المتغير number أفضل من index لأننا بدأنا العداد من 1 ونستخدمه للعرض فقط.
ماذا تعيد enumerate فعلًا؟
إذا كتبت متغيرًا واحدًا بدل تفكيك القيمتين، ستلاحظ أن كل عنصر ناتج هو tuple مكوّن من رقم وقيمة:
names = ["Ahmed", "Sara"]
for pair in enumerate(names):
print(pair)
الناتج:
(0, 'Ahmed')
(1, 'Sara')
لذلك كتابة for index, name in enumerate(names) هي عملية تفكيك مباشرة لهذه الأزواج.
هل enumerate تعمل مع List فقط؟
لا. enumerate() تعمل مع أي كائن قابل للتكرار، مثل Tuple أو النصوص، وليست مقصورة على القوائم. لكننا نركز هنا على List لأن هذا هو الاستخدام الأكثر ارتباطًا بموضوع المقال.
for index, letter in enumerate("Python"):
print(index, letter)
استخدام enumerate للعثور على عنصر أثناء المرور
إذا كنت تمر على قائمة وتريد تنفيذ شيء عند العثور على قيمة معينة، يمكنك استخدام enumerate() لمعرفة موقعها أثناء الحلقة:
products = ["Keyboard", "Mouse", "Monitor", "USB Cable"]
for index, product in enumerate(products):
if product == "Monitor":
print(f"Found at index {index}")
break
الناتج:
Found at index 2
أما إذا كان هدفك الأساسي هو البحث داخل القائمة باستخدام in أو index()، فراجع
بايثون بالمثال 10: البحث عن عنصر داخل List.
enumerate لا تعني list.index()
هناك فرق بين الأداتين:
| الأداة | ماذا تفعل؟ | متى تستخدمها؟ |
|---|---|---|
enumerate(items) |
تعطيك رقمًا وقيمة أثناء المرور على العناصر | عندما تعمل داخل حلقة وتحتاج الاثنين |
items.index(value) |
تبحث عن أول موقع لقيمة معينة داخل القائمة | عندما تريد موقع قيمة معروفة |
أخطاء شائعة عند استخدام enumerate
1. اعتبار start=1 فهرسًا حقيقيًا
إذا استخدمت start=1 فلا تسمِّ الرقم الناتج index إذا كنت ستستخدمه للوصول إلى القائمة، لأنه أصبح عدادًا يبدأ من 1 وليس الفهرس الحقيقي.
2. توقع List مباشرة من enumerate
كتابة enumerate(names) لا تنشئ List جديدة. إذا أردت رؤية الأزواج كلها للتعلّم أو الفحص، استخدم list(enumerate(names)).
3. استخدام enumerate عندما لا تحتاج الرقم
إذا كنت تحتاج إلى العنصر فقط، فهذا أبسط:
names = ["Ahmed", "Sara", "Omar"]
for name in names:
print(name)
4. استخدام فهارس يدوية دون حاجة
إذا كنت تكتب range(len(items)) فقط للحصول على العنصر ورقمه، فراجع إن كانت enumerate() ستجعل الكود أوضح. وهي تساعد أيضًا على تجنب بعض أخطاء الفهارس؛ راجع
حل خطأ IndexError list index out of range.
أسئلة شائعة عن enumerate في بايثون
من أي رقم تبدأ enumerate؟
تبدأ من 0 افتراضيًا، ويمكن تغيير العداد باستخدام start.
هل start=1 يجعل أول عنصر في index رقم 1؟
لا. هو يجعل عداد enumerate() يبدأ من 1، لكن الفهرس الحقيقي لأول عنصر في List يبقى 0.
هل enumerate ترجع List؟
لا. ترجع كائن enumerate قابلًا للتكرار. يمكنك تحويله إلى List باستخدام list() إذا احتجت ذلك.
متى أستخدم enumerate بدل range؟
استخدم enumerate() عندما تحتاج إلى الرقم والعنصر أثناء المرور. واستخدم range() عندما تكون الأرقام نفسها هي ما تريد توليده أو التحكم فيه.
روابط مفيدة
- أساسيات بايثون 8: شرح Lists في Python
- أساسيات بايثون 12: شرح Loops في Python
- شرح List Comprehension في بايثون
- مشكلة وحل 5: IndexError list index out of range
- توثيق بايثون الرسمي لدالة enumerate
خلاصة المقال
دالة enumerate() مفيدة عندما تحتاج إلى المرور على عناصر iterable والحصول على عداد وقيمة العنصر في الوقت نفسه. تبدأ من الصفر افتراضيًا، ويمكن تغيير بداية العداد باستخدام start.
استخدمها بدل range(len(list)) عندما يكون هدفك فقط قراءة رقم مع العنصر، وتذكر أن start=1 يغيّر العداد وليس الفهرس الحقيقي للقائمة.
{alertSuccess} القاعدة العملية: إذا احتجت إلى العنصر فقط فاستخدمfor item in items، وإذا احتجت إلى الرقم والعنصر معًا فاستخدمenumerate().
تمرين بسيط لك
لديك قائمة درجات. اطبع رقم الطالب بدءًا من 1 مع درجته، ثم اطبع أيضًا الفهرس الحقيقي لكل درجة.
grades = [85, 92, 78, 90]
for index, grade in enumerate(grades):
student_number = index + 1
print(f"Student {student_number} - index {index} - grade {grade}")
