2017-02-10 25 views
2

В настоящее время я использую список строк с именами функций, чтобы зафиксировать поток моего программного обеспечения:Использование уменьшить перебрать список функций и вызывать каждый один

flow = [ 
    "func1", 
    "func2", 
    "func3", 
    "func4", 
    "func5" 
] 

Тогда я итерацию над потоком и звоните каждый проходящие варианты:

options = {} 
[getattr(__import__(phase), phase)(options) for phase in flow] 

Я хотел бы знать, если это возможно, чтобы сделать то же самое, но избежать побочных эффектов, с помощью уменьшения. В настоящее время этот подход приводит к тому, что функции получают этот параметр, но не обязательно возвращать параметры для следующей функции, поэтому я изменяю параметры, объявленные в другой области.

Спасибо.

+2

Как вы строите этот список? Не могли бы вы просто поместить объекты функции в этот список '[func1, func2, ...]' Это сделало бы его намного проще –

+0

Почему было бы намного проще? Я бы просто удалил атрибуты get и import. –

+0

В цикле for бы были побочные эффекты, и я хочу закончить программное обеспечение, используя код возврата из последней функции. Я имею в виду, что если программное обеспечение преуспеет, последняя функция будет возвращать 0, то есть все нормально –

ответ

1

Вы можете использовать functools.reduce (который иногда называют fold в других языках функционального программирования, например Haskell), чтобы действительно вызвать функцию.

В этом случае, однако вам нужно будет определить функцию принимая два параметра: старое значение аккумулятор и сам элемент. Вы просто игнорируете старое значение и вызываете функцию на элементе.

Таким образом, для обобщенной функции f(x), вы можете сделать это с помощью:

functools.reduce(lambda _,x:f(x),list,initializer=0) 

Так что в вашем случае это будет:

options = {} 
functools.reduce(lambda _,phase:getattr(__import__(phase),phase)(options),flow,initializer=0) 

EDIT:

перечитав ваш вопрос, мне кажется, что каждая из функций принимает вход options и генерирует «новый» вариант s, который должен быть передан следующей функции. Ну, возврат первой функции - это первый параметр lambda следующей функции. Таким образом, вы можете сложить вместе, как:

first_options = {} 
functools.reduce(lambda options,phase:getattr(__import__(phase),phase)(options),flow,initializer=first_options) 

Это приведет к чему-то что эквивалентно:

options_0 = first_options 
options_1 = getattr(__import__(phase),flow[0])(options_0) 
options_2 = getattr(__import__(phase),flow[1])(options_1) 
# ... 
return options_n 

, но, конечно, это происходит внутриreduce.

+0

Как использовать параметры в качестве инициализатора? –

+0

@CelixOderix: вы имеете в виду, что * old * функция создает * новые * опции для следующего? –

+0

Да! Прекрасно, это именно то, что я пытался сделать! –

0

поэтому сокращение принимает одну функцию, скажем reduce_func, которая принимает 2 аргумента. Когда он проходит через список, он принимает первые два элемента в качестве параметров reduce_func для первого вызова, а затем для каждого последующего вызова использует возвращаемое значение в качестве первого параметра и следующее значение в списке в качестве второго параметра. Это значит, для вас, reduce_func должен быть следующим

def reduce_func(param, f): 
    return f(param) 

и ваш список должен быть следующим:

[options, func1, func2, func3, func4] 

Теперь, я использовал список функций и не использовать импорт.Вместо f вы можете пройти в [module].[function] в виде строки (вызовите param что-то вроде func_str), и сделайте некоторое расщепление и внутри reduce_func как некоторые настроены.