Несмотря на то, что генераторы в основном используют ключевое слово yield для возврата очередного значения, return из них никуда не делся. При использовании функции как генератора return позволяет досрочно его завершить.

Слегка модифицируем наш генератор: теперь он завершается автоматически, если очередное число оказалось больше 100000:

from collections.abc import Iterator

def pow_two(max_pow: int) -> Iterator:
    cur_pow = 0
    while cur_pow <= max_pow:
        yield 2 ** cur_pow
        cur_pow += 1

        # Если следующее число больше 10000,
        # прерываем итератор
        if 2 ** cur_pow > 100000:
            return

# Попробуем вывести степени двойки от 2^0 до 2^100
for i in pow_two(100):
    print(i)

При этом на самом деле выведутся только числа от 1 до 65536, потому что 131072 (следующая степень двойки) больше 100000:

1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536

Если переписать цикл for, то можно заметить, что на самом деле ключевое слово return в генераторах выбрасывает уже знакомое нам исключение StopIteration:

from collections.abc import Iterator

def pow_two(max_pow: int) -> Iterator:
    cur_pow = 0
    while cur_pow <= max_pow:
        yield 2 ** cur_pow
        cur_pow += 1
        if 2 ** cur_pow > 100000:
            return 'Next number is greater than 100000'

pt = pow_two(100)
while True:
    print(next(pt))

На экран выведется следующее:

1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
Traceback (most recent call last):
  File "main.py", line 15, in <module>
    print(next(pt))
StopIteration: Next number is greater than 100000

Process finished with exit code 1

Если указать после return какое-то значение, оно выведется вместе с исключением в качестве пояснения.

<aside> 👉 Можно заметить, что и без явного return генератор рано или поздно вернёт StopIteration. Это происходит потому, что в конце функции всегда происходит неявный return без каких-либо значений.

</aside>