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

Какой метод отвечает за получение следующего элемента в итераторе?

2.2 Middle🔥 181 комментариев
#Python Core

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

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

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

Какой метод отвечает за получение следующего элемента в итераторе

Метод __next__() отвечает за получение следующего элемента в итераторе. Это специальный метод (dunder method), который вызывается встроенной функцией next() или в цикле for.

Основной механизм

# __next__() — это метод итератора
class Counter:
    def __init__(self, max):
        self.current = 0
        self.max = max
    
    def __iter__(self):
        """Возвращает сам итератор."""
        return self
    
    def __next__(self):
        """Получает следующий элемент."""
        if self.current >= self.max:
            raise StopIteration  # Сигнал конца итерации
        self.current += 1
        return self.current

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

# Вариант 1: явный вызов next()
print(next(counter))  # 1 — вызывает __next__()
print(next(counter))  # 2
print(next(counter))  # 3
# next(counter)  # Вызовет StopIteration

# Вариант 2: цикл for (неявно вызывает __next__())
counter2 = Counter(3)
for num in counter2:
    print(num)  # 1, 2, 3

StopIteration — сигнал конца

Когда next() больше не может вернуть элемент, оно должно поднять исключение StopIteration:

class Range:
    def __init__(self, max):
        self.current = 0
        self.max = max
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current >= self.max:
            raise StopIteration  # Конец итерации
        self.current += 1
        return self.current

# Демонстрация
r = Range(2)
print(next(r))  # 1
print(next(r))  # 2
try:
    print(next(r))  # Вызывает StopIteration
except StopIteration:
    print("Итератор исчерпан")

Iterator vs Iterable

Важно различать два понятия:

# Iterable — объект, который ИМЕЕТ __iter__()
# Возвращает итератор
list_items = [1, 2, 3]  # Iterable
iterator = iter(list_items)  # Получили итератор через __iter__()

# Iterator — объект, который ИМЕЕТ __iter__() и __next__()
# Может получать следующий элемент
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):  # Iterable
        return self
    
    def __next__(self):  # Iterator — получает следующий элемент
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value

my_iter = MyIterator([10, 20, 30])
print(next(my_iter))  # 10 — вызвало __next__()
print(next(my_iter))  # 20
print(next(my_iter))  # 30

Использование в цикле for

class Alphabet:
    def __init__(self, letters):
        self.letters = letters
        self.index = 0
    
    def __iter__(self):
        return self  # Возвращает итератор (сам себя)
    
    def __next__(self):
        if self.index >= len(self.letters):
            raise StopIteration
        letter = self.letters[self.index]
        self.index += 1
        return letter

# Цикл for неявно вызывает:
# 1. __iter__() чтобы получить итератор
# 2. __next__() для каждой итерации
# 3. Ловит StopIteration чтобы завершить цикл

alphabet = Alphabet('ABC')
for char in alphabet:
    print(char)  # A, B, C

Встроенные итераторы Python

# List
list_iter = iter([1, 2, 3])
print(next(list_iter))  # 1 — вызвало __next__() встроенного класса list_iterator
print(next(list_iter))  # 2

# String
str_iter = iter("ABC")
print(next(str_iter))  # 'A'
print(next(str_iter))  # 'B'

# Range
range_iter = iter(range(3))
print(next(range_iter))  # 0
print(next(range_iter))  # 1

# Dict
dict_iter = iter({'a': 1, 'b': 2})
print(next(dict_iter))  # 'a' (ключи)
print(next(dict_iter))  # 'b'

# Enumerate
enum_iter = iter(enumerate(['x', 'y']))
print(next(enum_iter))  # (0, 'x')
print(next(enum_iter))  # (1, 'y')

Generator — особый тип итератора

Генератор — это функция, которая использует yield вместо return. Она автоматически имеет __iter__() и __next__():

# Обычный итератор
class FileReader:
    def __init__(self, filename):
        self.file = open(filename)
    
    def __iter__(self):
        return self
    
    def __next__(self):
        line = self.file.readline()
        if not line:
            raise StopIteration
        return line

# Генератор — то же самое, но проще
def file_reader(filename):
    with open(filename) as f:
        for line in f:
            yield line  # yield — это return, но сохраняет состояние

# Использование (одинаковое)
for line in file_reader('data.txt'):
    print(line)

Практические примеры

Пример 1: Итератор по файлу

class FileIterator:
    def __init__(self, filename):
        self.file = open(filename, 'r')
        self.closed = False
    
    def __iter__(self):
        return self
    
    def __next__(self):
        line = self.file.readline()
        if not line:
            self.file.close()
            self.closed = True
            raise StopIteration  # Конец файла
        return line.strip()

# Использование
for line in FileIterator('config.txt'):
    print(f"Config: {line}")

Пример 2: Итератор с состоянием

class Fibonacci:
    def __init__(self, limit):
        self.limit = limit
        self.a, self.b = 0, 1
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.a > self.limit:
            raise StopIteration
        value = self.a
        self.a, self.b = self.b, self.a + self.b
        return value

# Использование
for num in Fibonacci(100):
    print(num)  # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89

Пример 3: Итератор по БД

class DatabaseIterator:
    def __init__(self, db_connection, query):
        self.cursor = db_connection.cursor()
        self.cursor.execute(query)
    
    def __iter__(self):
        return self
    
    def __next__(self):
        row = self.cursor.fetchone()
        if row is None:
            self.cursor.close()
            raise StopIteration
        return row

# Использование
db = sqlite3.connect('data.db')
for row in DatabaseIterator(db, "SELECT * FROM users"):
    print(row)

Особенности next()

class SafeIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        # Не рекомендуется использовать try/except для контроля flow
        # ❌ Плохо
        try:
            value = self.data[self.index]
            self.index += 1
            return value
        except IndexError:
            raise StopIteration
        
        # ✅ Хорошо
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value

# Важно: __next__() должно быть эффективным
# Каждый вызов — это потенциально дорогая операция

Как Python вызывает next()

class Demo:
    def __init__(self):
        self.count = 0
    
    def __iter__(self):
        print("__iter__() вызван")
        return self
    
    def __next__(self):
        print(f"__next__() вызван (count={self.count})")
        if self.count >= 2:
            raise StopIteration
        self.count += 1
        return self.count

print("Начало цикла:")
for val in Demo():
    print(f"Получено значение: {val}")

# Вывод:
# Начало цикла:
# __iter__() вызван
# __next__() вызван (count=0)
# Получено значение: 1
# __next__() вызван (count=1)
# Получено значение: 2
# __next__() вызван (count=2)  <- Вызовет StopIteration

Заключение

__next__() — это метод, который:

  • Отвечает за получение следующего элемента итератора
  • Вызывается неявно функцией next() и циклом for
  • Должен поднимать StopIteration когда элементы закончились
  • Работает вместе с __iter__() для создания итерируемого объекта

Это фундаментальный механизм Python для работы с последовательностями и потоками данных.