FA-TOOLS — Header Component
آموزش enumerate و zip در پایتون با مثال

آموزش enumerate و zip در پایتون با مثال

سلام رفیق برنامه‌نویس! اگه دنبال راه‌هایی هستی که کدهات تمیزتر، کارآمدتر و پایتونی‌تر باشن، جای درستی اومدی. قراره امروز با دو تا از توابع دوست‌داشتنی پایتون یعنی enumerate و zip آشنا بشیم که مثل دو تا ابزار فوق‌العاده، کار رو برات حسابی راحت می‌کنن. آماده‌ای کدنویسی‌تو به مرحله بعدی ببری؟ در ضمن، اگه دنبال کلی اسنیپت و کد آماده پایتون هستی که کارت رو راه بندازه، حتماً یه سر به صفحه اسنیپت‌های پایتون ما بزن؛ کلی گنج اونجا منتظرته! و برای ابزارهای بیشتر، از فروشگاه ابزارها دیدن کن.

نقشه راه سریع: enumerate و zip در یک نگاه!

آموزش enumerate و zip در پایتون با مثال — تصویر 1
🌟 ویژگی 🔍 enumerate() 🔗 zip()
کاربرد اصلی افزودن شماره ترتیب (اندیس) به آیتم‌ها هنگام پیمایش ترکیب آیتم‌ها از چندین Iterable (به صورت موازی)
خروجی (اندیس, آیتم) (آیتم۱ از لیست۱, آیتم۲ از لیست۲, …)
مثال ساده for i, item in enumerate(my_list): for a, b in zip(list1, list2):
پارامتر start بله، برای شروع اندیس از عددی غیر از صفر خیر
طول خروجی همانند طول ورودی برابر با کوتاه‌ترین Iterable ورودی

حالا که یه دید کلی پیدا کردی، بزن بریم تا عمیق‌تر شیرجه بزنیم توی جزئیات هر کدوم!

چرا اصلا به enumerate و zip نیاز داریم؟ کجای کارمون گیر می‌افتن؟

آموزش enumerate و zip در پایتون با مثال — تصویر 2

حتماً تا حالا برات پیش اومده که داری یه لیست یا یه رشته رو پیمایش (iterate) می‌کنی و غیر از خود آیتم، به شماره ترتیب (اندیس) اون آیتم هم نیاز داری. مثلاً می‌خوای بگی “سومین میوه سیبه”. یا شاید دو تا لیست از اطلاعات مرتبط داری و می‌خوای آیتم‌های متناظرشون رو همزمان کنار هم ببینی و باهاشون کار کنی؛ مثلاً لیست اسم‌ها و لیست نمره‌ها. بدون enumerate و zip باید با اندیس‌دهی دستی و حلقه‌های تو در تو، کدی بنویسی که هم طولانی‌تره، هم احتمال خطا توش بیشتره، و هم خوانایی کمتری داره. اینجاست که این دو تا یار پایتونی میان و کد ما رو حسابی مرتب و تمیز می‌کنن.

enumerate چیه و چطوری کار می‌کنه؟

آموزش enumerate و zip در پایتون با مثال — تصویر 3

تصور کن داری یه لیست از دوستات رو چک می‌کنی. می‌خوای هم اسم دوستت رو بدونی و هم اینکه چندمین دوست تو لیسته. اینجا enumerate مثل یه دستیار باهوش عمل می‌کنه. وقتی یه Iterable (مثل لیست، تاپل، رشته و…) رو بهش می‌دی، اون موقع پیمایش، علاوه بر خود آیتم، یه اندیس هم بهت برمی‌گردونه. این اندیس از صفر شروع میشه، مگر اینکه خودت بهش بگی از کجا شروع کنه.

enumerate در عمل: سینتکس و کاربردها

سینتکس enumerate خیلی سادست:


enumerate(iterable, start=0)
    

همونطور که می‌بینی، دو تا پارامتر می‌گیره: iterable که همون چیزیه که می‌خوای پیمایش کنی و start که یه پارامتر اختیاریه و می‌تونی باهاش اندیس شروع رو تعیین کنی. اگه نذاریش، پیش‌فرض از صفر شروع میشه.

مثال ۱: پیمایش لیست با اندیس

فرض کن یه لیست از میوه‌ها داری و می‌خوای شماره هر میوه رو هم چاپ کنی:


my_fruits = ["سیب", "موز", "پرتقال", "هندوانه"]

print("--- میوه‌های مورد علاقه من ---")
for index, fruit in enumerate(my_fruits):
    print(f"{index + 1}. {fruit}")

# خروجی:
# --- میوه‌های مورد علاقه من ---
# 1. سیب
# 2. موز
# 3. پرتقال
# 4. هندوانه
    

دیدین چقدر راحت بود؟ دیگه نیازی نیست یه متغیر counter تعریف کنی و هر بار تو حلقه زیادش کنی. enumerate خودش کار رو برات انجام میده.

مثال ۲: تغییر اندیس شروع با پارامتر start

اگه بخوای شماره‌گذاری از ۱ شروع بشه به جای صفر، کافیه start=1 رو به enumerate بدی:


my_items = ["قلم", "دفتر", "پاک‌کن"]

for count, item in enumerate(my_items, start=1):
    print(f"شماره {count}: {item}")

# خروجی:
# شماره 1: قلم
# شماره 2: دفتر
# شماره 3: پاک‌کن
    

enumerate و خوانایی کد

یکی از مهم‌ترین مزایای enumerate، افزایش خوانایی کده. به جای اینکه مجبور باشی یه حلقه for معمولی بنویسی و بعدش با my_list[index] به آیتم‌ها دسترسی پیدا کنی، enumerate جفت (pair) اندیس و آیتم رو مستقیم بهت میده. این باعث میشه کدت مثل یک داستان خونده بشه و بفهمی دقیقاً چه اتفاقی داره میوفته.

مقایسه حلقه For معمولی با enumerate

حلقه For معمولی (بدون enumerate) با استفاده از enumerate

my_list = ['A', 'B', 'C']
for i in range(len(my_list)):
    print(f"اندیس {i}: {my_list[i]}")
                    

my_list = ['A', 'B', 'C']
for i, item in enumerate(my_list):
    print(f"اندیس {i}: {item}")
                    
معایب:
– نیاز به range(len(...))
– دسترسی به آیتم با my_list[i] (غیرمستقیم)
– کدی با خوانایی کمتر
مزایا:
– کد کوتاه‌تر و تمیزتر
– دسترسی مستقیم به اندیس و آیتم
– خوانایی بسیار بالاتر (پایتونیک)

zip چیه و چطوری کار می‌کنه؟

حالا فرض کن دو تا جعبه داری: تو یکی اسم دانشجوهاست و تو اون یکی نمره‌هاشون. می‌خوای این دو تا جعبه رو به صورت موازی باز کنی و هر بار اسم و نمره یک دانشجو رو با هم برداری. zip دقیقاً همین کارو برات انجام میده! چندین Iterable رو می‌گیره و آیتم‌های متناظرشون رو کنار هم قرار میده و به صورت یه تاپل بهت برمی‌گردونه. اسمش هم از زیپ لباس میاد که دو تا ردیف دندونه رو به هم وصل می‌کنه.

zip در عمل: سینتکس و کاربردها

سینتکس zip هم خیلی ساده‌ و مستقیمه:


zip(iterable1, iterable2, ...)
    

zip می‌تونه هر تعداد Iterable رو به عنوان ورودی بگیره.

مثال ۱: ترکیب دو لیست

دو تا لیست داریم: اسم دانشجوها و نمراتشون:


students = ["علی", "سارا", "رضا"]
grades = [18, 19.5, 17]

for student, grade in zip(students, grades):
    print(f"{student} نمره {grade} گرفته است.")

# خروجی:
# علی نمره 18 گرفته است.
# سارا نمره 19.5 گرفته است.
# رضا نمره 17 گرفته است.
    

به همین سادگی تونستیم اطلاعات مرتبط رو با هم ترکیب کنیم. zip یه شیء از نوع “zip object” برمی‌گردونه که خودش یه iterator هست. اگه بخوای نتیجه رو به صورت لیست ببینی، باید اونو به list() تبدیل کنی:


names = ["آبی", "قرمز", "زرد"]
codes = [101, 102, 103]

zipped_data = zip(names, codes)
print(list(zipped_data))

# خروجی:
# [('آبی', 101), ('قرمز', 102), ('زرد', 103)]
    

مثال ۲: ترکیب بیشتر از دو لیست

zip محدود به دو لیست نیست و می‌تونه هر تعداد Iterable رو با هم ترکیب کنه:


products = ["لپ‌تاپ", "موبایل", "هدفون"]
prices = [1200, 800, 150]
stocks = [10, 25, 5]

for product, price, stock in zip(products, prices, stocks):
    print(f"{product}: قیمت ${price}, موجودی: {stock} عدد")

# خروجی:
# لپ‌تاپ: قیمت $1200, موجودی: 10 عدد
# موبایل: قیمت $800, موجودی: 25 عدد
# هدفون: قیمت $150, موجودی: 5 عدد
    

نکته مهم: طول لیست‌ها در zip

zip تا زمانی که کوتاه‌ترین Iterable ورودی آیتم داشته باشه، ادامه پیدا می‌کنه. آیتم‌های اضافی در Iterableهای بلندتر نادیده گرفته میشن. این نکته تو بعضی شرایط می‌تونه مهم باشه:


list_a = [1, 2, 3, 4, 5]
list_b = ['a', 'b', 'c'] # لیست کوتاه‌تر

zipped_result = list(zip(list_a, list_b))
print(zipped_result)

# خروجی:
# [(1, 'a'), (2, 'b'), (3, 'c')]
# آیتم‌های 4 و 5 از list_a نادیده گرفته شدند.
    

کاربردهای پیشرفته‌تر zip

ساخت دیکشنری از دو لیست

یکی از کاربردهای خیلی خوب zip، ساختن دیکشنری از دو لیست (یکی برای کلیدها و یکی برای مقادیر) هستش:


keys = ["نام", "سن", "شهر"]
values = ["مریم", 30, "تهران"]

person_info = dict(zip(keys, values))
print(person_info)

# خروجی:
# {'نام': 'مریم', 'سن': 30, 'شهر': 'تهران'}
    

Unzipping (باز کردن زیپ!)

با استفاده از عملگر * (unpacking operator) می‌تونی یه لیست از تاپل‌ها رو که قبلاً با zip ساخته شده، دوباره “باز” کنی و به لیست‌های اصلی برگردونی. این یه ترفند باحاله که تو بعضی سناریوها خیلی به کارت میاد:


zipped_points = [(1, 2), (3, 4), (5, 6)]

x_coords, y_coords = zip(*zipped_points)

print(f"مختصات X: {list(x_coords)}")
print(f"مختصات Y: {list(y_coords)}")

# خروجی:
# مختصات X: [1, 3, 5]
# مختصات Y: [2, 4, 6]
    

اینجا *zipped_points باعث میشه تاپل‌ها به صورت آرگومان‌های جداگانه به zip فرستاده بشن، یعنی معادل zip((1, 2), (3, 4), (5, 6)) که خروجی رو به شکل مطلوب ما میده.

تفاوت‌های کلیدی enumerate و zip: کی کدومو استفاده کنیم؟

با اینکه هر دو برای کار با Iterableها کاربرد دارن و کد رو بهینه‌تر می‌کنن، اما هدفشون کاملاً متفاوته:

  • enumerate: وقتی به اندیس آیتم در کنار خود آیتم نیاز داری، از enumerate استفاده کن. هدفش اضافه کردن یه شمارنده به Iterable موجوده.
  • zip: وقتی می‌خوای آیتم‌های متناظر از چندین Iterable جداگانه رو با هم ترکیب کنی و همزمان پردازششون کنی، zip بهترین انتخابه. هدفش همگام‌سازی و ترکیب Iterableهاست.

یادت باشه، enumerate یک Iterable می‌گیره، ولی zip حداقل دو تا (و معمولاً بیشتر).

نکات حرفه‌ای و بهترین شیوه‌ها

  • ژنراتورها (Generators): هم enumerate و هم zip اشیای ژنراتور (iterator) برمی‌گردونن. این یعنی آیتم‌ها رو “در لحظه” تولید می‌کنن و حافظه کمتری مصرف می‌کنن. اگه فقط یه بار می‌خوای روی خروجی اونا پیمایش کنی، نیازی به تبدیلشون به لیست با list() نیست.
  • خوانایی کد: همیشه سعی کن کدهایی بنویسی که بقیه برنامه‌نویس‌ها (یا خودت در آینده) راحت بفهمن. استفاده از enumerate و zip به جای حلقه‌های دستی با اندیس، به شدت به خوانایی کمک می‌کنه و کدتو پایتونی‌تر می‌کنه.
  • استفاده از itertools.zip_longest: اگه می‌خوای zip وقتی طول Iterableها متفاوته، آیتم‌های بلندتر رو هم حفظ کنه و جای خالی‌ها رو با یه مقدار پیش‌فرض پر کنه، می‌تونی از zip_longest ماژول itertools استفاده کنی. یه ابزار فوق‌العاده کاربردی تو پروژه‌های بزرگ!


from itertools import zip_longest

list_a = [1, 2, 3, 4, 5]
list_b = ['a', 'b', 'c']

# با zip_longest، جاهای خالی با None پر میشن
zipped_long = list(zip_longest(list_a, list_b))
print(zipped_long)

# خروجی:
# [(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]

# می‌تونی مقدار پر کننده (fillvalue) رو هم تعیین کنی:
zipped_filled = list(zip_longest(list_a, list_b, fillvalue='-'))
print(zipped_filled)

# خروجی:
# [(1, 'a'), (2, 'b'), (3, 'c'), (4, '-'), (5, '-')]
    

استفاده از itertools نشون میده که تو یه برنامه‌نویس حرفه‌ای هستی و بهینگی و کنترل رو در اولییت قرار میدی.

در ضمن، اگه نیاز به اسنیپت‌های CSS یا JS یا HTML هم داشتی، حتماً از کدهای آماده CSS، اسنیپت‌های JavaScript و تکه‌های کد HTML ما دیدن کن. کلی چیز بدرد بخور پیدا می‌کنی! برای دیدن همه اسنیپت‌ها هم می‌تونی به صفحه اصلی اسنیپت‌ها سر بزنی.

عیب‌یابی سریع: مشکلات رایج و راه‌حل‌ها

مشکل ۱: enumerate همیشه از صفر شروع میشه

سناریو: می‌خوای لیست آیتم‌هات رو از شماره ۱ نشون بدی، ولی enumerate از ۰ شروع می‌کنه.

راه‌حل: از پارامتر start در enumerate استفاده کن.


my_list = ["نوروز", "یلدا"]
for idx, val in enumerate(my_list, start=1):
    print(f"مناسبت {idx}: {val}")
# خروجی:
# مناسبت 1: نوروز
# مناسبت 2: یلدا
        

مشکل ۲: zip لیست‌های با طول متفاوت رو کوتاه می‌کنه

سناریو: دو تا لیست با طول متفاوت داری و zip آیتم‌های اضافی لیست بلندتر رو نادیده می‌گیره. می‌خوای همه آیتم‌ها رو داشته باشی.

راه‌حل: از itertools.zip_longest استفاده کن و اگه خواستی fillvalue رو تعیین کن.


from itertools import zip_longest

names = ["آرش", "بهنام"]
ages = [25, 30, 22] # لیست ages بلندتره

combined_data = list(zip_longest(names, ages, fillvalue="نامشخص"))
print(combined_data)
# خروجی:
# [('آرش', 25), ('بهنام', 30), ('نامشخص', 22)]
        

مشکل ۳: zip یا enumerate یکبار مصرف هستند

سناریو: بعد از اینکه یه بار روی خروجی zip یا enumerate پیمایش کردی، دیگه نمی‌تونی دوباره ازش استفاده کنی.

راه‌حل: اگه لازمه چند بار از خروجی استفاده کنی، اون رو به یه لیست تبدیل کن.


data = ['a', 'b', 'c']
enum_obj = enumerate(data)

# پیمایش اول
for i, item in enum_obj:
    print(f"اولین بار: {i}-{item}")

# پیمایش دوم (اینجا چیزی چاپ نمیشه چون enum_obj مصرف شده)
print("n--- پیمایش دوم ---")
for i, item in enum_obj:
    print(f"دومین بار: {i}-{item}")

# راه‌حل: تبدیل به لیست برای استفاده چندباره
enum_list = list(enumerate(data))
print("n--- استفاده چندباره ---")
for i, item in enum_list:
    print(f"بار اول لیست: {i}-{item}")
for i, item in enum_list:
    print(f"بار دوم لیست: {i}-{item}")
        

مشکل ۴: “TypeError: ‘int’ object is not iterable”

سناریو: به enumerate یا zip یه عدد (یا هر چیز غیر Iterable دیگه) دادی و خطا گرفتی.

راه‌حل: مطمئن شو ورودی‌هایی که به این توابع میدی، حتماً Iterable باشن (مثل لیست، تاپل، رشته، دیکشنری، ست و…).


# کد اشتباه:
# for i, val in enumerate(123):
#     print(val)
# خروجی: TypeError: 'int' object is not iterable

# کد صحیح:
for i, val in enumerate([1, 2, 3]): # تبدیل به لیست
    print(f"{i}: {val}")
# خروجی:
# 0: 1
# 1: 2
# 2: 3
        

امیدوارم این بخش عیب‌یابی بهت کمک کرده باشه تا با خیال راحت از این توابع قدرتمند پایتون استفاده کنی. و اگه نیاز به کمک یا مشاوره داری، هر وقت خواستی می‌تونی با این شماره تماس بگیری: 09202232789.

حرف آخر و یه جمع‌بندی دوستانه

خوب رفیق، رسیدیم به پایان مسیرمون! دیدیم که enumerate و zip چقدر می‌تونن کدنویسی ما رو ساده‌تر، تمیزتر و پایتونی‌تر کنن. یادگیری و استفاده از این توابع نه تنها باعث میشه کدهات حرفه‌ای‌تر به نظر بیان، بلکه باعث میشه کمتر با باگ‌های مربوط به اندیس‌دهی دستی سر و کله بزنی و زمان بیشتری برای فکر کردن به منطق اصلی برنامه‌ات داشته باشی. این‌ها ابزارهایی هستن که هر برنامه‌نویس پایتون باید تو جعبه ابزارش داشته باشه و به شکل صحیح ازشون استفاده کنه. برای اینکه این مفاهیم برات جا بیفته، حتماً خودت دست به کد شو و با مثال‌های مختلف تمرین کن. خوشحال میشیم نظرات و تجربه‌هات رو هم با ما به اشتراک بذاری!

سوالات متداول (FAQ)

❓ آیا enumerate فقط برای لیست‌هاست؟

نه رفیق! enumerate برای هر نوع Iterable مثل لیست، تاپل، رشته، ست، دیکشنری و حتی اشیایی که خودت iterator می‌سازی کار می‌کنه.

zip با لیست‌های نامساوی چکار می‌کنه؟

zip تا زمانی که کوتاه‌ترین Iterable ورودی آیتم داشته باشه، ترکیب کردن رو ادامه میده. آیتم‌های اضافی در Iterableهای بلندتر نادیده گرفته میشن. اگه می‌خوای همه آیتم‌ها حفظ بشن، از itertools.zip_longest استفاده کن.

❓ آیا خروجی enumerate و zip رو میشه دوباره استفاده کرد؟

نه، این توابع اشیای ژنراتور برمی‌گردونن که یک بار مصرف هستن. اگه نیاز داری چندین بار از خروجی استفاده کنی، حتماً اون رو به یه لیست یا تاپل تبدیل کن (مثلاً list(enumerate(...))).

❓ آیا می‌تونم enumerate و zip رو با هم استفاده کنم؟

کاملاً! تو می‌تونی zip رو با خروجی enumerate ترکیب کنی، یا enumerate رو روی خروجی zip اعمال کنی. مثلاً:


names = ["آرمین", "بهار"]
scores = [90, 85]

for i, (name, score) in enumerate(zip(names, scores)):
    print(f"شماره {i+1}: {name} با نمره {score}")
# خروجی:
# شماره 1: آرمین با نمره 90
# شماره 2: بهار با نمره 85
            

 

Table of Contents

آخرین نوشته‌ها