Generator در پایتون
generatorها توابعی هستند که میتوان در حین اجرا آنها را متوقف کرد و سپس ادامه داد. این توابع شیءای را برمیگردانند که میتوان روی آنها پیمایش کرد. بر خلاف لیستها، generatorها lazy (کندرو) هستند که موجب میشود که محاسبه و ارزیابی یک عبارت تا جای ممکن به تاخیر افتاده و در اولین زمانی که دسترسی به آن نیاز بود، محاسبه شود. این توابع هنگام کار با مجموعه دادههای بزرگ استفاده از حافظه را کارآمدتر میکنند.
تفاوت generator با توابع معمولی پایتون
- برای فراخوانی مقادیر بعدی در generator از متد () next استفاده می کنیم.
- در توابع معمولی برای برگرداندن مقادیر از return استفاده میکنیم ولی در generator از yield (دستور yield به این صورت عمل میکند که تابع را متوقف و وضعیت آن را ذخیره میکند تا در آینده از همانجایی که متوقف شده بود به کار خود ادامه دهد.)
- generatorها همچنین iterator هم هستند، یعنی اینکه کلاسهایی که تعریف میکنیم متد ()__iter__ در آن تعریف شده باشند.
مثالی از generator
در کد زیر تابع generator داریم که لیستی را به عنوان آرگومان میگیرد و جمع اعداد عنصرهای آن را به ما برمیگرداند:
def myGenerator(l): total = 0 for n in l: total += n yield total mygenerator = myGenerator([15,10, 7]) print(mygenerator) print(next(mygenerator)) print(next(mygenerator)) print(next(mygenerator)) ''' Output: <generator object myGenerator at 0x0000026B84B6C150> 15 25 32 '''
میبینیم که به ازای هر بار فراخوانی متد next، مقدار جدیدی به ما نمایش داده میشود. اگر دوباره تابع را فرواخوانی کنیم، خطا ای مبنی بر اینکه “نمیتوانید پیمایش کنید” دریافت خواهید کرد.
Traceback (most recent call last): File "generators.py", line 13, in <module> print(next(mygenerator)) StopIteration
Generator Comprehension
همانند لیستها، generatorها را هم میتوان به این طریق نوشت، با این تفاوت که به جای لیست، generator بر میگرداند.
char_list = ['a', 'b', 'c', 'd'] mygenerator = (x for x in char_list) print(mygenerator) print(next(mygenerator)) print(next(mygenerator)) print(next(mygenerator)) print(next(mygenerator)) ''' Output: a b c d '''
همچنین به صورت زیر هم میتوان نوشت:
char_list = ['a', 'b', 'c', 'd'] mygenerator = (x for x in char_list) print(mygenerator) for i in mygenerator: print(i) ''' Output: a b c d '''
مقایسه list comprehension و generator comprehension
در کد زیر مقایسهای بین حافظهی اشغال شده بین list و generator خواهیم داشت.
import sys g = (i * 2 for i in range(10000)) l = [i * 2 for i in range(10000)] print("Generator Size : ", sys.getsizeof(g)) print("List Size : ", sys.getsizeof(l)) ''' Output: Generator Size : 88 List Size : 87624 '''
همانطور که از خروجی معلوم است، مصرف حافظه در generatorها بسیار کمتر از لیست است. اتفاقی که در اینجا میافتد این است که به جای اینکه تمام دادهها را در حافظه قرار بدهیم و از آن استفاده کنیم، فقط آن قسمتی را که نیاز داریم در حافظه میگذاریم.
با اینکه generatorها حافظهی کمی مصرف میکنند ولی باعث کند شدن اجرای کد می شوند.
import cProfile cProfile.run("sum((i * 2 for i in range(10000000)))") cProfile.run("sum([i * 2 for i in range(10000000)])") ''' Output: 100000005 function calls in 22.033 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 100000001 11.519 0.000 11.519 0.000 <string>:1(<genexpr>) 1 0.000 0.000 22.033 22.033 <string>:1(<module>) 1 0.000 0.000 22.033 22.033 {built-in method builtins.exec} 1 10.513 10.513 22.033 22.033 {built-in method builtins.sum} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} ----------------------------------------------------------------- 5 function calls in 15.513 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 11.194 11.194 11.194 11.194 <string>:1(<listcomp>) 1 1.386 1.386 15.513 15.513 <string>:1(<module>) 1 0.000 0.000 15.513 15.513 {built-in method builtins.exec} 1 2.932 2.932 2.932 2.932 {built-in method builtins.sum} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} '''
22 ثانیه زمان برد تا generator اجرا شود ولی با لیست به زمان 15 ثانیه رسیدیم.
جمع بندی
generatorها به ما کمک میکنند که هر زمان که به مقداری نیاز داریم، آن را درخواست کنیم.این قابلیت در استفاده از داده های حجیم کارآمدتر است ولی در مقابل زمان را فدای حافظه کردیم. پس در نظر داشته باشید زمانی که با کمبود حافظه مواجه هستیم، استفاده از generatorها کمک شایانی به ما خواهد کرد.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.