Функция обратного вызова (callback) или итератор в Python
Раньше мы видели, как функции обратного вызова (колбеки) могут быть лучше простых функций, но есть и другие варианты. Мы можем создать, вероятно, неограниченный итератор, который будет обходить элементы нашей последовательности, делая код еще более понятным, чем даже решение с колбеками.
Решение с колбеком
Просто для напоминания - вот наше решение с колбеком. У нас есть функция 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, который его как-то остановит.
Решение выглядит проще, чем вариант с колбеками.

Published on 2016-03-19