generator ها در پایتون
Generatorها یکی از ویژگیهای مهم پایتون هستند که برای ایجاد اشیاء قابل تکرار (iterables) استفاده میشوند، اما برخلاف لیستها، همه مقادیر را همزمان در حافظه نگه نمیدارند. آنها مقادیر را در لحظه (on-demand) تولید میکنند و به همین دلیل مصرف حافظه بسیار کمتری دارند.
چرا generator؟
فرض کنید قرار است لیستی از میلیونها عدد را تولید کنید. اگر از لیست معمولی استفاده کنید، تمام مقادیر در حافظه ذخیره میشوند که میتواند باعث کندی یا حتی خطای کمبود حافظه شود. اما با generator میتوانید همان خروجی را بهصورت مرحلهای تولید کنید بدون آنکه همه چیز در حافظه بار شود.
ساخت generator با استفاده از yield
تابعی که از yield
استفاده میکند به جای اینکه مانند return
یک مقدار برگرداند و خاتمه یابد، یک generator ایجاد میکند که میتواند مقدار بعدی را در هر مرحله با next()
یا یک حلقه مانند for
ارائه دهد.
def countdown():
i = 5
while i > 0:
yield i
i -= 1
for num in countdown():
print(num)
خروجی:
5
4
3
2
1
تفاوت yield با return
تابعهایی که return
دارند تنها یکبار اجرا میشوند و مقدار را برمیگردانند. در مقابل، توابعی که از yield
استفاده میکنند اجرای خود را متوقف کرده و حالت (state) را حفظ میکنند، بنابراین میتوانند در فراخوانی بعدی ادامه یابند.
مثال ساده: تولید اعداد زوج
def even_numbers(n):
for i in range(n):
if i % 2 == 0:
yield i
print(list(even_numbers(10))) # خروجی: [0, 2, 4, 6, 8]
مثال کاربردیتر: خواندن فایلهای بزرگ خط به خط
در فایلهای متنی بزرگ، بارگذاری کل فایل در حافظه میتواند مشکلساز باشد. با generator میتوان خط به خط فایل را بدون فشار حافظه خواند:
def read_large_file(filename):
with open(filename, 'r') as file:
for line in file:
yield line.strip()
for line in read_large_file('log.txt'):
if 'ERROR' in line:
print(line)
مثال بینهایت: تولید بیپایان عدد 7
def infinite_sevens():
while True:
yield 7
for i in infinite_sevens():
print(i) # این حلقه بینهایت اجرا میشود
مقایسه با لیستهای معمولی
فرض کنید نیاز دارید 100 میلیون عدد را تولید و بررسی کنید:
# استفاده از لیست (مصرف بالای حافظه)
nums = [i for i in range(100_000_000)]
# استفاده از generator (مصرف پایین حافظه)
def generate_nums():
for i in range(100_000_000):
yield i
در مثال بالا، generator فقط عدد جاری را در حافظه نگه میدارد، اما لیست تمام اعداد را.
نکته پایانی
Generatorها انتخابی عالی برای پردازش دادههای حجیم یا بینهایت هستند. با حفظ عملکرد بهینه و صرفهجویی در مصرف حافظه، میتوانند باعث افزایش کارایی قابل توجه در بسیاری از برنامهها شوند. اگر نیازی به دسترسی تصادفی (index-based) به عناصر ندارید، generator راهحل مناسبی است.