به آموزشگاه مجازی سینا خوش آمدید!

آموزش ژنراتور(generator) در پایتون

امتیاز
(0)

ژنراتورها(Generators) در پایتون، تابع‌هایی هستند که می‌توانند اجرای خود را متوقف(pause) یا از‌سرگیری(resume) کنند. 

هنگامی که یک تابع ژنراتور فراخوانی می‌شود، یک آبجکت ژنراتور(generator) را برمی‌گرداند که یک شیء تکرارکننده(iterator) محسوب می‌شود. با انجام این کار، هنوز کدهای درون این تابع اجرا نمی‌شوند، بلکه فقط کامپایل می‌شوند. این تابع تنها وقتی اجرا می‌شود که روی آن حلقه بزنیم. 

مثال شماره 1

یک تابع ژنراتور ساده:

def my_generator():
  yield 1
  yield 2
  yield 3

for value in my_generator():
  print(value)

نتیجه:

1
2
3
امتحان کنید

نکته: ژنراتورها به ما امکان می‌دهند تا روی داده‌ها حلقه بزنیم؛ بدون اینکه تمام داده‌ها(dataset) را در حافظه(memory) ذخیره کنیم. در ژنراتورها، به جای استفاده از دستور return، از کلمه‌ی کلیدی yield (به معنی واگذاری) استفاده می‌شود.  


کلمه‌ی کلیدی yield

کلمه‌ی کلیدی yield باعث می‌شود یک تابع به یک ژنراتور(generator) تبدیل شود. هنگامی که با دستور yield مواجه می‌شویم، وضعیت تابع ذخیره(save) می‌شود و مقدارِ مورد نظر برگردانده(return) می‌شود. دفعه‌ی بعد که ژنراتور فراخوانی می‌شود، از جایی که متوقف شده بود ادامه پیدا می‌کند. 

مثال شماره 2

یک ژنراتور که اعداد را واگذار(yield) می‌کند:

def count_up_to(n):
  count = 1
  while count <= n:
    yield count
    count += 1

for num in count_up_to(5):
  print(num)

نتیجه:

1
2
3
4
5
امتحان کنید
 

نکته: برخلاف دستور return که باعث می‌شود تابع به پایان برسد، دستور yield آن تابع را متوقف(pause) می‌کند و چندین بار می‌توانیم آن را (دوباره) فراخوانی کنیم. 

 


ژنراتورها در حافظه صرفه‌جویی می‌کنند

ژنراتورها در استفاده از حافظه موثر هستند؛ زیرا آنها به جای اینکه همه چیز را در حافظه ذخیره کنند، مقادیر را در حین اجرا(on-the-fly) تولید می‌کنند. ژنراتورها در مجموعه‌داده‌های(dataset) بزرگ، باعث صرفه جویی در حافظه(memory) می‌شوند:

مثال شماره 3

استفاده از ژنراتورها برای دنباله‌های بزرگ:

def large_sequence(n):
  for i in range(n):
    yield i

# این دستور یک میلیون عدد را در حافظه ایجاد نمی کند

gen = large_sequence(1000000)
print(next(gen))
print(next(gen))
print(next(gen))

نتیجه:

0
1
2
امتحان کنید

در مثال بالا، ما یک عدد بزرگ یعنی یک میلیون را به تابع ژنراتور دادیم، اما این تابع یک میلیون بار اجرا نشده است، بلکه به تعدادی که آن را صدا بزنیم(به تعداد نیاز) اجرا می‌شود و دوباره متوقف می‌شود. اما اگر این عدد را به یک تابع عادی بدهیم، آن تابع یک میلیون بار اجرا خواهد شد و آن اعداد را در حافظه ذخیره می‌کند. 


استفاده از تابع next() به همراه ژنراتورها

ما می‌توانیم به صورت دستی با استفاده از تابع next() روی یک ژنراتور حلقه بزنیم:

مثال شماره 4

def simple_gen():
  yield "Emil"
  yield "Tobias"
  yield "Linus"

gen = simple_gen()
print(next(gen))
print(next(gen))
print(next(gen))

نتیجه:

Emil
Tobias
Linus
امتحان کنید

هنگامی که مقدار دیگری برای واگذاری(yield) وجود نداشته باشد، ژنراتور، خطای StopIteration را ایجاد می‌کند:

مثال شماره 5

def simple_gen():
  yield 1
  yield 2

gen = simple_gen()
print(next(gen))
print(next(gen))
print(next(gen))  # را ایجاد می کند StopIteration این دستور خطای 

نتیجه:

1
2

Traceback (most recent call last):
  File "./prog.py", line 8, in <module>
StopIteration
امتحان کنید

استفاده از عبارت‌های ژنراتور(Generator Expressions)

مشابه با روش احاطه‌ی لیست(list comprehensions)، ما می‌توانیم با استفاده از عبارت‌های ژنراتور، به همراه پرانتزها به جای براکت‌ها، ژنراتورها را ایجاد کنیم:

مثال شماره 6

روش احاطه‌ی لیست در مقابل عبارت ژنراتور:

# روش احاطه ی لیست - یک لیست ایجاد می کند
list_comp = [x * x for x in range(5)]
print(list_comp)

# عبارت ژنراتور - یک ژنراتور را ایجاد می کند
gen_exp = (x * x for x in range(5))
print(gen_exp)
print(list(gen_exp))

نتیجه:

[0, 1, 4, 9, 16]
<generator object <genexpr> at 0x...>
[0, 1, 4, 9, 16]
امتحان کنید

مثال شماره 7

استفاده از یک عبارت ژنراتور  به همراه تابع sum:

# محاسبه ی جمع توان های 2 بدون ایجاد یک لیست
total = sum(x * x for x in range(10))
print(total)

نتیجه:

285
امتحان کنید

ایجاد دنباله‌ی فیبوناچی با ژنراتور

با استفاده از ژنراتورها در پایتون، می‌توانیم دنباله‌ی فیبوناچی را ایجاد کنیم. این کد می‌تواند به تولید مقادیر به طور نامحدود ادامه دهد؛ بدون اینکه حافظه‌ی زیادی را اشغال کند:

مثال شماره 8

تولید 100 عدد فیبوناچی:

def fibonacci():
  a, b = 0, 1
  while True:
    yield a
    a, b = b, a + b

# Get first 100 Fibonacci numbers
gen = fibonacci()
for _ in range(100):
  print(next(gen))

نتیجه:

0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
2971215073
4807526976
7778742049
12586269025
20365011074
32951280099
53316291173
86267571272
139583862445
225851433717
365435296162
591286729879
956722026041
1548008755920
2504730781961
4052739537881
6557470319842
10610209857723
17167680177565
27777890035288
44945570212853
72723460248141
117669030460994
190392490709135
308061521170129
498454011879264
806515533049393
1304969544928657
2111485077978050
3416454622906707
5527939700884757
8944394323791464
14472334024676221
23416728348467685
37889062373143906
61305790721611591
99194853094755497
160500643816367088
259695496911122585
420196140727489673
679891637638612258
1100087778366101931
1779979416004714189
2880067194370816120
4660046610375530309
7540113804746346429
12200160415121876738
19740274219868223167
31940434634990099905
51680708854858323072
83621143489848422977
135301852344706746049
218922995834555169026
امتحان کنید

استفاده از متدهای ژنراتور(Generator Methods)

زنراتورها در پایتون، می‌توانند متدهای خاصی برای کنترل‌های پیشرفته‌تر داشته باشند:

متد send()

متد send() به ما امکان می‌دهد تا یک مقدار را به ژنراتور ارسال کنیم:

مثال شماره 9

def echo_generator():
  while True:
    received = yield
    print("Received:", received)

gen = echo_generator()
next(gen)  # آماده کردن ژنراتور
gen.send("Hello")
gen.send("World")

نتیجه:

Received: Hello
Received: World
امتحان کنید

متد close()

متد close() باعث می‌شود ژنراتور متوقف(stop) شود:

مثال شماره 10

def my_gen():
  try:
    yield 1
    yield 2
    yield 3
  finally:
    print("Generator closed")

gen = my_gen()
print(next(gen))
gen.close()

نتیجه:

1
Generator closed
امتحان کنید

 


منبع: www.w3schools.com/python

 

  • بازدید: 48

نوشتن دیدگاه

لطفا نظرات خود را بیان کنید. به سوالات در سریع ترین زمان پاسخ داده خواهد شد.اما به نکات زیر توجه کنید:
1. سعی کنید نظرات شما مرتبط با مقاله ی مورد نظر باشد، در غیر این صورت پاسخ داده نخواهد شد.
2. سوالات خود را به صورت کوتاه بیان کنید و از پرسیدن چند سوال به طور همزمان خودداری کنید.
3. سوال خود را به طور واضح بیان کنید و از کلمات مبهم استفاده نکنید.

ارسال