Iterators و Generators 🔄
یاد میگیریم چطور دادههای بزرگ رو بدون مشکل حافظه پردازش کنیم!
Iterator: راهی هوشمند برای پیمایش دادهها!
Iterator یه شیء هست که میتونه روی مجموعهای از دادهها حرکت کنه و هر بار یکی از عناصر رو برگردونه. فکر کن مثل یه نشانگر که روی لیست حرکت میکنه و هر بار یه عنصر رو نشون میده. در پایتون، هر چیزی که بشه روش حلقه زد (مثل لیست، تاپل، رشته) یه Iterator محسوب میشه!
# ساخت یک Iterator از لیست
numbers = [1, 2, 3, 4, 5]
iterator = iter(numbers)
print("استفاده از next() برای دریافت عناصر:")
print(next(iterator)) # خروجی: 1
print(next(iterator)) # خروجی: 2
print(next(iterator)) # خروجی: 3
# استفاده در حلقه for
print("\nاستفاده در حلقه:")
for num in numbers:
print(f"عدد: {num}")
# ساخت Iterator سفارشی
class CountDown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start <= 0:
raise StopIteration
self.start -= 1
return self.start + 1
# استفاده از Iterator سفارشی
print("\nشمارش معکوس:")
countdown = CountDown(5)
for num in countdown:
print(f"شمارش: {num}")
Generator: جادوگر تولید داده!
Generator یه نوع خاص از تابع هست که میتونه اجراش رو متوقف کنه و بعداً از همون نقطه ادامه بده! با کلمه کلیدی `yield` به جای `return` استفاده میکنیم. این کار باعث میشه بتونیم دادههای بزرگ رو بدون اینکه کل حافظه رو پر کنیم، تولید کنیم. فوقالعاده مفیده برای پردازش فایلهای بزرگ!
# Generator ساده برای تولید اعداد
def number_generator(n):
"""تولید اعداد از 0 تا n"""
for i in range(n):
print(f"تولید عدد: {i}")
yield i # yield به جای return
print(f"ادامه پس از yield {i}")
# استفاده از Generator
print("=== استفاده از Generator ===")
gen = number_generator(3)
print(f"نوع generator: {type(gen)}")
# دریافت مقادیر یکی یکی
print("\nدریافت مقادیر:")
print(next(gen)) # خروجی: 0
print(next(gen)) # خروجی: 1
print(next(gen)) # خروجی: 2
# Generator برای دنباله فیبوناچی
def fibonacci_generator(limit):
"""تولید دنباله فیبوناچی تا حد مشخص"""
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
print("\n=== دنباله فیبوناچی ===")
for num in fibonacci_generator(100):
print(num, end=" ")
# Generator Expression (مثل List Comprehension)
print("\n\n=== Generator Expression ===")
squares = (x**2 for x in range(5))
print(f"نوع: {type(squares)}")
for square in squares:
print(f"مربع: {square}")
Generator های پیشرفته: قدرت واقعی!
Generator ها میتونن با هم ترکیب بشن، داده دریافت کنن و حتی exception هم handle کنن! این قابلیتها باعث میشه بتونیم pipeline های پردازش داده خیلی قدرتمند بسازیم.
# Generator که داده دریافت میکنه
def data_processor():
"""پردازشگر داده که میتونه داده دریافت کنه"""
total = 0
count = 0
while True:
# دریافت داده از بیرون
value = yield total / count if count > 0 else 0
if value is None:
break
total += value
count += 1
print(f"دریافت شد: {value}, میانگین فعلی: {total/count:.2f}")
# استفاده از Generator دریافتکننده
print("=== Generator دریافتکننده ===")
processor = data_processor()
next(processor) # راهاندازی اولیه
# ارسال دادهها
processor.send(10)
processor.send(20)
processor.send(30)
result = processor.send(None) # پایان
print(f"نتیجه نهایی: {result}")
# Generator برای خواندن فایل بزرگ
def read_large_file(file_path, chunk_size=1024):
"""خواندن فایل بزرگ به صورت تکهای"""
try:
with open(file_path, 'r', encoding='utf-8') as file:
while True:
chunk = file.read(chunk_size)
if not chunk:
break
yield chunk
except FileNotFoundError:
yield "فایل پیدا نشد!"
# Pipeline پردازش داده
def filter_numbers(text_generator):
"""فیلتر کردن اعداد از متن"""
import re
for text in text_generator:
numbers = re.findall(r'\d+', text)
for num in numbers:
yield int(num)
def square_numbers(number_generator):
"""مربع کردن اعداد"""
for num in number_generator:
yield num ** 2
# ترکیب Generator ها
print("\n=== Pipeline پردازش ===")
sample_text = ["سلام 123 دنیا", "عدد 456 و 789", "پایان 999"]
text_gen = (text for text in sample_text)
number_gen = filter_numbers(text_gen)
squared_gen = square_numbers(number_gen)
for squared in squared_gen:
print(f"مربع: {squared}")
تمرین عملی
یک Generator بنویسید که:
- اعداد اول (Prime Numbers) را تولید کند
- بتوان حد بالایی برای آن تعیین کرد
- هر عدد اول را همراه با شمارهاش برگرداند
- از Iterator pattern استفاده کند
class PrimeGenerator:
"""Generator برای تولید اعداد اول"""
def __init__(self, limit=100):
self.limit = limit
self.primes = []
def __iter__(self):
return self
def __next__(self):
if not hasattr(self, 'current'):
self.current = 2
self.index = 0
while self.current <= self.limit:
if self.is_prime(self.current):
prime = self.current
self.primes.append(prime)
self.current += 1
self.index += 1
return (self.index, prime)
self.current += 1
raise StopIteration
def is_prime(self, n):
"""بررسی اول بودن عدد"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
# Generator function برای اعداد اول
def prime_generator(limit):
"""Generator function برای تولید اعداد اول"""
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
count = 0
num = 2
while num <= limit:
if is_prime(num):
count += 1
yield (count, num)
num += 1
# استفاده از کلاس
print("=== استفاده از کلاس PrimeGenerator ===")
primes_class = PrimeGenerator(50)
for index, prime in primes_class:
print(f"{index}. عدد اول: {prime}")
if index >= 5: # فقط 5 تا نشان بده
break
# استفاده از Generator Function
print("\n=== استفاده از Generator Function ===")
for index, prime in prime_generator(30):
print(f"{index}. عدد اول: {prime}")
# ترکیب با سایر Generator ها
print("\n=== مربع اعداد اول ===")
primes = prime_generator(20)
squared_primes = ((i, p**2) for i, p in primes)
for index, squared in squared_primes:
print(f"{index}. مربع عدد اول: {squared}")
چالش پیشرفته
یک سیستم پردازش لاگ بسازید که:
- از Generator برای خواندن فایلهای بزرگ استفاده کند
- Pipeline پردازش برای فیلتر و تجزیه لاگها داشته باشد
- آمار real-time از دادهها ارائه دهد
- حافظه را بهینه مدیریت کند
این چالش نیاز به ترکیب Generator ها با پردازش متن و مدیریت حافظه دارد. سعی کنید خودتان حل کنید!