Насколько я понимаю, у вас есть поток видеокадров, и вы пытаетесь создать конвейер функций обработки, которые изменяют поток. Различные функции обработки могут изменять количество кадров, поэтому один входной кадр может привести к нескольким выходным кадрам, или несколько входных кадров могут быть использованы до создания одного выходного кадра. Некоторые функции могут быть 1: 1, но это не то, на что вы можете рассчитывать.
Ваша текущая реализация использует функции генератора для всей обработки. Выходная функция выполняет итерации по цепочке, и каждый шаг обработки в конвейере запрашивает кадры из предыдущего, используя итерацию.
Функция, которую вы пытаетесь написать прямо сейчас, является своего рода избирательным обходом. Вы хотите, чтобы некоторые кадры (удовлетворяющие некоторому условию) передавались какой-то уже существующей функции генератора, а другие кадры пропускали обработку и просто go прямо в вывод. К сожалению, это, вероятно, невозможно сделать с генераторами Python. Протокол итерации просто недостаточно сложен для его поддержки.
Во-первых, можно сделать это за 1: 1 с генераторами, но вы не можете легко обобщить до n
: 1 или 1: n
случаев. Вот как это может выглядеть для 1: 1:
def selective_processing_1to1(processing_func, condition, input_iterable):
processing_iterator = processing_func(iter(lambda: input_value, object()))
for input_value in input_iterator:
if condition(input_value):
yield next(processing_iterator)
else:
yield input_value
На этапе создания processing_iterator
проделана большая работа. Используя форму с двумя аргументами iter
с функцией lambda
и сторожевым объектом (который никогда не будет получен), я создаю бесконечный итератор, который всегда возвращает текущее значение локальной переменной input_value
. Затем я передаю этот итератор в функцию processing_func
. Я могу выборочно вызвать next
для объекта генератора, если я хочу применить обработку, которую фильтр представляет к текущему значению, или я могу просто получить значение самостоятельно, не обрабатывая его.
Но поскольку это работает только на один кадр за раз, это не подходит для фильтров n
: 1 или 1: n
(и я даже не хочу думать о m
: n
видах сценариев ios).
«Выглядимый» итератор, который позволяет вам видеть, каким будет следующее значение, перед тем, как вы его итерируете, может позволить вам поддерживать ограниченную форму выборочной фильтрации для n
: 1 процессов (то есть где возможно переменная n
входные кадры go в один выходной кадр). Ограничение состоит в том, что вы можете выполнять выборочную фильтрацию только для первого из n
кадров, которые будут использованы обработкой, остальные будут приняты без того, чтобы у вас была возможность проверить их в первую очередь. Может быть, этого достаточно?
Во всяком случае, вот как это выглядит:
_sentinel = object()
class PeekableIterator:
def __init__(self, input_iterable):
self.iterator = iter(input_iterable)
self.next_value = next(self.iterator, _sentinel)
def __iter__(self):
return self
def __next__(self):
if self.next_value != _sentinel:
return_value = self.next_value
self.next_value = next(self.iterator, _sentinel)
return return_value
raise StopIteration
def peek(self): # this is not part of the iteration protocol!
if self.next_value != _sentinel:
return self.next_value
raise ValueError("input exhausted")
def selective_processing_Nto1(processing_func, condition, input_iterable):
peekable = PeekableIterator(input_iterable)
processing_iter = processing_func(peekable)
while True:
try:
value = peekable.peek()
print(value, condition(value))
except ValueError:
return
try:
yield next(processing_iter) if condition(value) else next(peekable)
except StopIteration:
return
Это так же хорошо, как мы можем практически сделать, когда функция обработки является генератором. Если бы мы хотели сделать больше, например, поддерживать обработку 1: n
, нам понадобился бы какой-то способ узнать, насколько большим будет n
, чтобы мы могли получить столько значений, прежде чем решить, будем ли мы передавать следующее входное значение или нет. Хотя вы можете написать собственный класс для обработки, который бы сообщал об этом, это, вероятно, менее удобно, чем простой повторный вызов функции обработки, как в вопросе.