Одним из альтернативных решений может быть использование инструмента рабочего процесса dask. Хотя синтаксически это не так весело, как ...
var
| do this
| then do that
... он по-прежнему позволяет вашей переменной течь вниз по цепочке, а использование dask дает дополнительное преимущество распараллеливания, где это возможно.
Вот как я использую dask для выполнения паттерна конвейерной цепочки:
import dask
def a(foo):
return foo + 1
def b(foo):
return foo / 2
def c(foo,bar):
return foo + bar
workflow = {'a_task':(a,1),
'b_task':(b,'a_task',),
'c_task':(c,99,'b_task'),}
dask.get(workflow,'c_task')
После работы с elixir я захотел использовать паттерн трубопроводов в Python. Это не совсем тот же шаблон, но он похож и, как я уже сказал, дает дополнительные преимущества распараллеливания; если вы скажете dask включить задачу в ваш рабочий процесс, которая не зависит от выполнения другими, они будут выполняться параллельно.
Если вам нужен более простой синтаксис, вы можете обернуть его чем-нибудь, что позаботится об именовании задач за вас. Конечно, в этой ситуации вам нужно, чтобы все функции принимали конвейер в качестве первого аргумента, и вы потеряете все преимущества параллелизации. Но если вас это устраивает, вы можете сделать что-то вроде этого:
def dask_pipe(initial_var, functions_args):
'''
call the dask_pipe with an init_var, and a list of functions
workflow, last_task = dask_pipe(initial_var, {function_1:[], function_2:[arg1, arg2]})
workflow, last_task = dask_pipe(initial_var, [function_1, function_2])
dask.get(workflow, last_task)
'''
workflow = {}
if isinstance(functions_args, list):
for ix, function in enumerate(functions_args):
if ix == 0:
workflow['task_' + str(ix)] = (function, initial_var)
else:
workflow['task_' + str(ix)] = (function, 'task_' + str(ix - 1))
return workflow, 'task_' + str(ix)
elif isinstance(functions_args, dict):
for ix, (function, args) in enumerate(functions_args.items()):
if ix == 0:
workflow['task_' + str(ix)] = (function, initial_var)
else:
workflow['task_' + str(ix)] = (function, 'task_' + str(ix - 1), *args )
return workflow, 'task_' + str(ix)
def foo(df):
return df[['a','b']]
def bar(df, s1, s2):
return df.columns.tolist() + [s1, s2]
def baz(df):
return df.columns.tolist()
import dask
import pandas as pd
df = pd.DataFrame({'a':[1,2,3],'b':[1,2,3],'c':[1,2,3]})
Теперь с помощью этой оболочки вы можете создать конвейер, соответствующий любому из этих синтаксических шаблонов:
как это:
workflow, last_task = dask_pipe(df, [foo, baz])
print(dask.get(workflow, last_task))
workflow, last_task = dask_pipe(df, {foo:[], bar:['string1', 'string2']})
print(dask.get(workflow, last_task))
crime_by_state %>% filter(State=="New York", Year==2005) ...
с конца Как dplyr заменить мои наиболее распространенные идиомы R .