مفهوم تابع در زبان های برنامه نویسی از مفهوم توابع ریاضی گرفته شده است که در ساده ترین حالت یک ورودی و یک خروجی دارد. y=ax+b تابعی است که x ورودی آن و y خروجی آن و a و b ضرایب (پارامترهای) تابع هستند.
تابع های برنامه نویسی می توانند هیچ، یک یا چندین ورودی داشته باشند و هیچ یا چندین خروجی داشته باشند. زمانی که یک تابع چیزی را برگشت دهد، این مقدار توسط عبارت return برگشت داده می شود. به عبارت دیگر درون بدنه تابع، محاسبات انجام می شود و سپس مقدار برگشت داده می شود.
فرض کنید می خواهید یک فایل بزرگ را بخوانید چه چیزی برای انجام چنین چیزی لازم است؟ بدون قطع حافظه اصلی یا RAM مهمترین چیز است زیرا فایل حجیم با تعداد بسیاری از خطوط، باید درون حافظه اصلی بارگذاری شود، پس احتمالا با کمبود حافظه مواجه خواهید شد.
MemoryError
در زبان پایتون یک تابع Generator، تابعی است که به جای برگشت دادن مقداری با عبارت return، از عبارت yield استفاده می کند بدین گونه که به جای برگشت دادن مقدار توسط return، برگشت دادن مقدار را به تاخیر می اندازد تا زمانی که تابع را استفاده (فراخوانی) کنیم. به عبارت دیگر استفاده به هنگام نیاز (فراخوانی)، هدف Generator ها است.
در Generator ها عبارت return وجود ندارد.
در کد زیر یک تابع معمولی برای بدست آوردن اعداد زوج میان صفر تا ۱۰۰۰۰ نمایش داده شده است. توجه کنید در اینجا نتیجه تابع در حافظه نگهداری می شود. بنابراین اگر تعداد محاسبات از ۱۰۰۰۰ تا ۱۰۰۰۰۰۰۰۰۰ افزایش پیدا کند، پس احتمالا سیستم با کمبود حافظه و از کار افتادن برنامه یا حتی سیستم عامل دچار خواهد شد.
در کد بالا (۱) به محض اجرای تابع ()print مقدار برگشتی از تابع نمایش داده می شود. در کد زیر یک Generator را نوشته ایم. توجه کنید تابعی Generator است که درون آن یک یا چندین عبارت yield باشد و از این رو عبارت yield بیرون از یک تابع بی معنی است.
تفاوت اصلی yield یا توابع Generator در این است که مقدار برگشتی یا مقدار محاسبه یا نتیجه محاسبه در حافظه نگه داشته نمی شود. توجه کنید در کد بالا (۲) پیش از متغیر number عبارت yield آورده شده است. همچنین در این مثال تنها یک عبارت yield پیش از مقدار مد نظر ما آورده شده است.
در شکل ۲، مقدار برگشتی تابع در متغیر output ریخته شده است و در خط بعدی می خواهیم آن را با تابع ()print نمایش دهیم ولی پیامی نشان داده می شود که این شی از نوع generator است. بنابراین باید شی Generator را توسط یکی از سه روش زیر پیمایش کنیم.
گفته شد که اشیا Generator از نوع تکرارپذیرها (Iterator) هستند و از این رو توسط حلقه تکرار for ... in قابل پیمایش هستند. در کد شکل زیر (۳) می خواهیم روی اشیا درون متغیر output (مربوط به شکل ۲) پیمایش انجام دهیم. بنابراین هر یک از عناصر چاپ شده یک عدد زوج خواهد بود.
گفته شد که اشیا Generator در حافظه اصلی نگهداری نمی شوند، بنابراین در کد شکل زیر که بلافاصله پس از کد شکل ۳ (حلقه for ... in) بالا انجام شده، متغیر output را به کمک تابع ()list به لیست تبدیل کردیم که دیگر این لیست دارای مقدارهای واقعی و غیر شی Generator هستند.
بنابراین چون اشیا Generator در حافظه نگهداری نمی شوند، پس به گونه ای یک بار مصرف هستند و از این رو در شکل زیر (۵) پس از اجرای کد حلقه شکل ۳، باید (البته تنهای برای تست در این نوشته) یک بار دیگر کد متغیر output را مانند شکل ۲ فراخوانی کنیم.
تابع ()next یکی از توابع درونی (Built-in) در پایتون است که بر روی تکرارپذیرها (Iterator) کاربرد دارد. ورودی آن یک تکرارپذیر و خروجی آن یک آیتم درون تکرارپذیر است و به همین روند، میتوان با فراخوانی ()next یکی یکی آیتم ها را نشان داد.
در کد بالا اولین آیتم توسط اولین تابع ()next نمایش داده شده که اولین عدد زوج یعنی عدد صفر است. به همین ترتیب دیگر آیتم های بعدی با هر بار فراخوانی تابع ()next فراخوانی شدند.
تابعی که به جای return عبارت yield را به کار برده باشد، یک Generator است که به صورت یک Iterator از اشیا Generator قابل پیمایش است. Generator ها هرگز در حافظه نگهداری نمی شوند و از این رو برای محاسبات سنگین مناسب هستند که نیاز به فضای RAM بالا دارند. یک نمونه از آنها، خواندن یک فایل متنیبزرگ با تعداد بسیاری خط است.
همچنین مقدار برگشتی یک تابع Generator تنها یک بار قابل مصرف است و درون یک فایل یا قطعه کد اگر جایی از کد استفاده و پیمایش شد، باید در صورت نیاز برای استفاده در همان کد، یک بار دیگر تابع Generator فراخوانی شود.