Раньше мы видели, как функции обратного вызова (колбеки) могут быть лучше простых функций, но есть и другие варианты. Мы можем создать, вероятно, неограниченный итератор, который будет обходить элементы нашей последовательности, делая код еще более понятным, чем даже решение с колбеками.
Решение с колбеком
Просто для напоминания - вот наше решение с колбеком. У нас есть функция fibonacci, которая проходит элементы последовательности,
и для каждого элемента вызывает переданную функцию check_17
.
examples/python/fibonacci_function_callback.py
#!/usr/bin/env python
from __future__ import print_function
def fibonacci(cb):
values = []
while(True):
if len(values) < 2:
values.append(1)
else:
values = [values[-1], values[-1] + values[-2]]
r = cb(values[-1])
if (r[0]):
return(r[1])
def check_17(v):
if v % 17 == 0:
return (True, v)
if v > 10000:
return (True, None)
return (False,)
if __name__ == '__main__':
res = fibonacci(check_17)
if (res != None):
print(res)
Тот факт, что мы должны иметь возможность передать функции fibonacci
сигнал, когда остановиться, делает наш код несколько сложнее, чем мы надеялись.
Мы должны возвращать массив, в котором первый элемент выполняет роль индикатора (True/False).
Создание Fibonacci-итератора
Давайте сделаем все наоборот и позволим пользователю вернуть контроль над циклом.
Мы создаем класс Fibonacci
, который будет итерабельным вследствие добавления
метода __iter__
, который просто возвращает объект,
и метода next
(В Python 3, думаю, это будет __next__
),
который возвращает следующий элемент.
Внутри объект содержит текущее состояние итерации. В нашем случае это значит, что он должен содержать последние два элемента последовательности.
examples/python/fibonacci_iterator.py
#!/usr/bin/env python
from __future__ import print_function
class Fibonacci(object):
def __init__(self):
self.values = []
def __iter__(self):
return self
def next(self):
if len(self.values) < 2:
self.values.append(1)
else:
self.values = [self.values[-1], self.values[-1] + self.values[-2]]
return self.values[-1]
for f in Fibonacci():
if f % 17 == 0:
print(f)
break
if f > 10000:
break
Вызов fib = Fibonacci()
создаст объект итератора, который мы можем использовать
в конструкции for in
для перебора элементов.
Поскольку это неограниченный итератор, то есть, он не имеет конца,
мы должны быть уверены, что есть какой-то код внутри цикла for
,
который его как-то остановит.
Решение выглядит проще, чем вариант с колбеками.