1️⃣ Generator Expressions
شبیه List Comprehension، ولی به جای فهرست، یه ژنراتور تولید میکنن که مقادیر رو یکییکی میده.
squares_gen = (x**2 for x in range(5))
for num in squares_gen:
print(num)
# Khoroji:
# 0
# 1
# 4
# 9
# 16
🔹 مقایسه با فهرست:
squares_list = [x**2 for x in range(5)]
print(squares_list) # Khoroji: [0, 1, 4, 9, 16]
# Ama generator:
squares_gen = (x**2 for x in range(5))
print(squares_gen) # Khoroji: <generator object <genexpr> at ...>
💡 نکته ریز:
🔻 ژنراتورها فقط یهبار قابل پیمایشان. بعد از پیمایش، خالی میشن:
squares_gen = (x**2 for x in range(5))
print(list(squares_gen)) # Khoroji: [0, 1, 4, 9, 16]
print(list(squares_gen)) # Khoroji: [] (chon khali shode)
💯 @PythonForYou 🧑💻👩💻
2️⃣ توابع ژنراتور با yield
با yield تو یه تابع، میتونی ژنراتور بسازی که مقادیر رو یکییکی برگردونه و حالت تابع رو حفظ کنه.
✨ مثال ساده:
def my_generator():
yield 1
yield 2
yield 3
gen = my_generator()
for num in gen:
print(num)
# Khoroji:
# 1
# 2
# 3
✨ مثال پیشرفتهتر (فیبوناچی):
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for num in fibonacci(6):
print(num)
# Khoroji:
# 0
# 1
# 1
# 2
# 3
# 5
💡 نکته ریز:
درواقع yield اجرای تابع رو متوقف میکنه و مقدار رو برمیگردونه، ولی حالت تابع رو حفظ میکنه.
برعکس return که تابع رو کامل تموم میکنه، yield منتظر فراخوانی بعدی میمونه.
💯 @PythonForYou 🧑💻👩💻
❓ چرا ژنراتورها؟ مزایا و کاربردها 🤔
🔸 صرفهجویی تو حافظه:
ژنراتورها مقادیر رو یکییکی تولید میکنن، نه یهجا:
import sys
gen = (x for x in range(1000000))
print(sys.getsizeof(gen)) # ~104 bytes
lst = [x for x in range(1000000)]
print(sys.getsizeof(lst)) # ~9000000 bytes
🔸 پشتیبانی از دادههای بینهایت:
میتونی دنبالههای نامحدود بسازی:
def infinite_numbers():
num = 0
while True:
yield num
num += 1
gen = infinite_numbers()
for _ in range(5):
print(next(gen))
# Khoroji: 0, 1, 2, 3, 4
🔸 ترکیب با توابع داخلی:
ژنراتورها با sum، max و غیره خوب کار میکنن:
print(sum(x for x in range(100))) # Khoroji: 4950
💯 @PythonForYou 🧑💻👩💻
4️⃣ نکات ریز و ترفندهای حرفهای
🔸 استفاده از ()next:
برای گرفتن مقدار بعدی ژنراتور:
gen = (x**2 for x in range(3))
print(next(gen)) # Khoroji: 0
print(next(gen)) # Khoroji: 1
print(next(gen)) # Khoroji: 4
🔸 مدیریت خطای StopIteration:
try:
gen = (x for x in range(2))
print(next(gen))
print(next(gen))
print(next(gen))
except StopIteration:
print("Generator tamoom shod! 🚫")
🔸 ترکیب با ()range:
evens_gen = (x for x in range(0, 10, 2))
print(list(evens_gen)) # Khoroji: [0, 2, 4, 6, 8]
🔸 ژنراتورهای تودرتو با yield from:
def nested_generator():
yield from [1, 2, 3]
yield from [4, 5, 6]
for num in nested_generator():
print(num)
# Khoroji: 1, 2, 3, 4, 5, 6
🔸 استفاده تو pipeline داده:
برای فیلتر کردن یا تبدیل دادهها بهصورت زنجیرهای:
def filter_evens():
for num in range(10):
if num % 2 == 0:
yield num
for num in filter_evens():
print(f"Zoj: {num}")
# Khoroji: Zoj: 0, Zoj: 2, Zoj: 4, Zoj: 6, Zoj: 8
💯 @PythonForYou 🧑💻👩💻
5️⃣ مثالهای کاربردی
🔸 تولید اعداد اول:
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
def prime_generator(limit):
for num in range(limit):
if is_prime(num):
yield num
for prime in prime_generator(20):
print(prime)
# Khoroji: 2, 3, 5, 7, 11, 13, 17, 19
🔸 ژنراتور برای دادههای بزرگ:
def large_data_generator():
for i in range(1000000):
yield i * 2
gen = large_data_generator()
for _ in range(5):
print(next(gen))
# Khoroji: 0, 2, 4, 6, 8
🔸 فیلتر کردن با ژنراتور:
numbers = [1, 2, 3, 4, 5, 6]
odds_gen = (x for x in numbers if x % 2 != 0)
print(list(odds_gen)) # Khoroji: [1, 3, 5]
—-—-—-—-—-—-—-—-—-—-—
6️⃣ نکات حرفهای
🔸 صرفهجویی در حافظه:
همیشه ژنراتورها رو به فهرست ترجیح بده برای دادههای بزرگ، مگر اینکه واقعاً به فهرست نیاز داشته باشی.
🔸 خوانایی کد:
اسمهای معنیدار برای ژنراتورها انتخاب کن (مثل evens_gen به جای g).
🔸 ترکیب با itertools:
برای کارهای پیچیدهتر، از ماژول itertools استفاده کن:
from itertools import islice
gen = (x**2 for x in range(100))
print(list(islice(gen, 5))) # Khoroji: [0, 1, 4, 9, 16]
🔸 مدیریت پایان ژنراتور:
همیشه آماده خطای StopIteration باش یا از حلقه for استفاده کن که خودش این خطا رو مدیریت میکنه.
💯 @PythonForYou 🧑💻👩💻