4

У меня есть сеть узлов, проходящих через структурированные данные. Для моей подзадачи, мы имеем эту ветвь - линейная последовательность узлов:Как создавать итераторы?

nodes = [source, n1, n2, n3, n4] 

Первый узел представляет собой генератор, каждый другой узел получает значения из входного узла и обеспечивает выходное значение. Текущая реализация - это простой get() из трубы и put() в канал, и на каждом узле есть отдельный поток (есть причина для этого). Я хочу изменить его на итератор yield.

И я хочу, чтобы оценить в следующим образом (если мы рассматриваем узел должен быть вызываемым):

for result in n4(n3(n2(n1(source()))): 
    print result 

Я полагаю, строительство контекста оценки, как это:

context = src 
for node in nodes[1:]: 
    context = pipe(context, node) 

for result in context: 
    print result 

Ограничения :

Я по-прежнему хочу иметь возможность использовать узлы отдельно - не вложенные, данные о трубопроводах другими способами, поскольку узлы может быть в отдельных потоках. Пример: [source, n1,n2] в одном потоке (может быть вложенным), [n3, n4] в другом (может быть вложенным), данные передаются между n2 и n3. Случай: может быть граф нелинейных узлов, где я хочу группировать ветви таким образом.

node должен быть класс, чтобы провести вычисление состояния

Как реализация context и pipe(context, node) может выглядеть? Или, если это можно решить по-другому, есть ли у вас какие-то намеки?

Может ли yield from в Python 3.3 (PEP380) помочь моему делу в любом случае?

ответ

2

Если вы хотите составить произвольное количество функций (или вызываемых), используйте compose_mult recipe из документации модуля functional.

Решение, которое использует, что:

from functional import compose, foldr, partial 
from itertools import imap 
compose_mult = partial(reduce, compose) 
chain_nodes = lambda nodes: imap(compose_mult(nodes[1:]), nodes[0]) 
chain_gen_nodes = lambda nodes: imap(compose_mult((g.send for g in nodes[1:])), nodes[0]) 


# equivalent not as a one-liner 
#def chain_nodes(nodes): 
# source = nodes[0] 
# composed_nodes = compose_mult(nodes[1:]) 
# return (composed_nodes(x) for x in source) 

Если узлы являются генераторами, которые принимают входные (через send), а затем использовать chain_gen_nodes, который извлекает свою функцию отправки.

Обратите внимание, однако, что один не разрешен для send для только что запущенного генератора (потому что он должен быть в точке yield для получения значения). Это то, что вам нужно будет решать самостоятельно, например, если у ваших генераторов yield значение фиктивного значения на их первой итерации и продвигайте их в какой-то момент, прежде чем отправлять их в chain_nodes. Или вы можете просто держать свои узлы в качестве обычных вызывающих.

Если вам не нужно продвигать Итераторов один шаг: next(izip(*nodes[1:]))

+0

Это то, что я написал в моем вопросе - то есть принцип, я хочу достичь. Проблема в том, что список узлов неизвестен до вычисления. Вот почему я перечислил узлы как массив 'nodes = [...]'. – Stiivi

+1

@Stiivi Это не то, что вы написали. Однако я обновил свой ответ. – Marcin

+0

Прошу прощения за то, что я недостаточно ясен и благодарю вас за ваше предложение - кажется, это полезное решение.Как вы думаете, это можно сделать с использованием стандартной библиотеки python («нет» или «слишком сложно», также принят простой ответ)? Я бы хотел избежать большего количества зависимостей (в этом случае «функционал»). – Stiivi