الدرس 6 من 8

Iterators و Generators

السر ورا تدريب الموديلات على داتا أكبر من الرامات.

الـ for بتشتغل إزاي من جوه؟

أي حاجة تقدر تلف عليها بـ for اسمها iterable (list، string، ملف...). الـ for من جوه بتطلب منها iterator، وتفضل تقول next() تاخد العنصر اللي بعده، لحد ما العناصر تخلص.

iterator.py
colors = ["red", "green", "blue"]
it = iter(colors)        # get an iterator

print(next(it))
print(next(it))
print(next(it))
# next(it) now would raise StopIteration -> the for loop stops here

المشكلة: الذاكرة

لو عندك ملف لوجز فيه ١٠ مليون سطر وقريته كله في list، الجهاز ممكن يهنج. الـ generator بيحل ده: بدل ما يجهز كل العناصر مرة واحدة، بيطلع عنصر عنصر وقت ما تطلبه. زي مطعم بيعمل الطلب وقت ما تطلبه، مش بيطبخ ألف طبق ويحطهم على الترابيزة.

الكلمة السحرية: yield

generator.py
def count_up_to(n):
    i = 1
    while i <= n:
        yield i          # pause here, hand out i, resume on next request
        i += 1

for number in count_up_to(3):
    print(number)

الفرق: return بترجع قيمة والدالة تخلص خالص. yield بترجع قيمة وتقف مؤقتاً مكانها، ولما تطلب العنصر اللي بعده تكمل من نفس النقطة.

شوف الفرق في الذاكرة بعينك

memory.py
import sys

as_list = [x * 2 for x in range(1_000_000)]   # builds ALL values now
as_gen = (x * 2 for x in range(1_000_000))    # () instead of [] -> generator

print(sys.getsizeof(as_list), "bytes")
print(sys.getsizeof(as_gen), "bytes")
💡 Generator expressionلو كتبت الـ comprehension بـ ( ) بدل [ ] بتبقى generator. لو هتلف على العناصر مرة واحدة بس، دي غالباً الأحسن.
🤖 مثال AI حقيقي: تقسيم الداتا لـ batchesالموديلات مش بتتدرب على الداتا كلها مرة واحدة، بتاخدها دفعات صغيرة اسمها batches. ده بالظبط اللي بيعمله الـ DataLoader في PyTorch، وده شكله مبسط:
batches.py
def make_batches(data, batch_size):
    for start in range(0, len(data), batch_size):
        yield data[start:start + batch_size]

images = [f"img_{i}.jpg" for i in range(1, 8)]

for batch in make_batches(images, batch_size=3):
    print("Training on:", batch)
⚠ الـ generator بيخلصالـ generator تلف عليه مرة واحدة بس. لو لفيت عليه تاني هتلاقيه فاضي. لو محتاج الداتا أكتر من مرة، استخدم list أو اعمل generator جديد.
الدرس اللي فات