← Назад к вопросам

Как превратить обычный класс в итерируемый в Python?

1.0 Junior🔥 191 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как сделать класс итерируемым в Python

Чтобы превратить обычный класс в итерируемый (то есть использовать его в цикле for), нужно реализовать специальные методы: __iter__() и __next__().

Способ 1: Метод __iter__() с __next__()

class CountUp:
    """Класс, который считает от 1 до N"""
    
    def __init__(self, max_value):
        self.max_value = max_value
        self.current = 0
    
    def __iter__(self):
        """Возвращает объект итератора (самого себя)"""
        self.current = 0
        return self
    
    def __next__(self):
        """Возвращает следующее значение"""
        if self.current < self.max_value:
            self.current += 1
            return self.current
        else:
            raise StopIteration  # Сигнал конца итерации

# Использование
counter = CountUp(5)
for number in counter:
    print(number)  # Output: 1, 2, 3, 4, 5

Что здесь происходит:

  • __iter__() вызывается один раз при входе в цикл for
  • __next__() вызывается на каждой итерации
  • Когда __next__() выбросит StopIteration, цикл завершится

Способ 2: Методы __iter__() возвращает отдельный итератор

Это более правильный подход, если класс нужно использовать несколько раз:

class CountUpIterator:
    """Отдельный класс-итератор"""
    
    def __init__(self, max_value):
        self.max_value = max_value
        self.current = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.max_value:
            self.current += 1
            return self.current
        raise StopIteration

class CountUp:
    """Итерируемый класс"""
    
    def __init__(self, max_value):
        self.max_value = max_value
    
    def __iter__(self):
        """Возвращает новый итератор при каждом вызове"""
        return CountUpIterator(self.max_value)

# Использование
counter = CountUp(3)

# Первый проход
for num in counter:
    print(num)  # Output: 1, 2, 3

# Второй проход (будет работать потому что каждый раз создаётся новый итератор)
for num in counter:
    print(num)  # Output: 1, 2, 3

Способ 3: Генератор (самый простой способ)

Вместо создания отдельного класса-итератора можно использовать функцию-генератор с yield:

class CountUp:
    """Итерируемый класс с использованием генератора"""
    
    def __init__(self, max_value):
        self.max_value = max_value
    
    def __iter__(self):
        """Генератор в методе __iter__"""
        for i in range(1, self.max_value + 1):
            yield i

# Использование
counter = CountUp(5)
for num in counter:
    print(num)  # Output: 1, 2, 3, 4, 5

# Можно применять несколько раз
for num in counter:
    print(num)  # Output: 1, 2, 3, 4, 5

Это наиболее чистый и читаемый способ.

Практический пример: итерирование по файлам в директории

import os
from pathlib import Path

class DirectoryIterator:
    """Класс для итерирования по файлам директории"""
    
    def __init__(self, directory_path):
        self.directory = Path(directory_path)
    
    def __iter__(self):
        """Генератор для обхода файлов"""
        for file in sorted(self.directory.glob("*.txt")):
            yield file.name

# Использование
files = DirectoryIterator(".")
for filename in files:
    print(f"Found: {filename}")

Добавление поддержки срезов с __getitem__

Можно сделать класс итерируемым даже без __iter__(), если реализовать __getitem__() с целочисленным индексом:

class SimpleList:
    """Класс с поддержкой индексирования"""
    
    def __init__(self, items):
        self.items = items
    
    def __getitem__(self, index):
        return self.items[index]
    
    def __len__(self):
        return len(self.items)

# Использование
my_list = SimpleList([10, 20, 30, 40])

for item in my_list:  # Python автоматически использует __getitem__
    print(item)  # Output: 10, 20, 30, 40

print(my_list[0])  # Output: 10
print(len(my_list))  # Output: 4

Рекомендации

  • Простые случаи → используй генератор (yield)
  • Сложная логика итерирования → реализуй __iter__() и __next__()
  • Нужна поддержка срезов → добавь __getitem__() и __len__()
  • Для читаемости → предпочитай отдельный класс-итератор вместо самоссылающегося __iter__()
Как превратить обычный класс в итерируемый в Python? | PrepBro