2015-03-25 3 views
0

Я пишу рекурсивную функцию, которая выглядит примерно так:Сухо и consisely написать рекурсивную функцию

def mah_recursive_function(some_arg, some_option=True): 
    if some_thing: 
     some_arg.doFancyStuff(); 
     mah_recursive_function(some_arg, 
           some_option=some_option 
     ) 
    elif some_thing: 
     some_arg.doOtherFancyStuff(); 
     mah_recursive_function(some_arg, 
           some_option=some_option 
     ) 

Очевидно, что эти some_option=some_option заданий действительно излишние, и, так как у меня есть более чем один постоянный вариант kwarg , избыточные задания становятся очень раздражающими.

from functools.magical_stuff import get_current_kwargs 
mah_recursive_function(
    some_arg, **get_current_kwargs() 
) 

Я бы предпочел не раздувать мои рекурсивные звонки с избыточными линиями. Каков наилучший способ сделать это?

+1

Не могли бы вы сократить это до минимального примера? Думаю, будет легче ответить и более полезно для будущих пользователей. – KobeJohn

+0

У меня не будет времени написать ответ, но ActiveState [имеет рецепт для него] (http://code.activestate.com/recipes/491265-automatic-recursion/). Я думаю, что они ключевыми являются то, что вам нужно будет делать копии ваших аргументов/kwargs в каждом рекурсивном вызове, иначе вы будете изменять args/kwargs для всех вызовов каждый раз, когда вы их модифицируете. – KobeJohn

ответ

2

Рассмотрим, используя функцию-обертку, чтобы избежать повторения:

def recursive_func_wrapper(arg, option=True): 
    def recursive_func(arg): 
     if option: recursive_func(new_arg) 
     else: recursive_func(new_arg2) 
    return recursive_func(arg) 

Ваш вариант автоматически распространяется (в качестве локальной переменной) к внутренней функции, которая может как обычно, без повторения аргумента option=.

0

Вот минимальный пример того, что, как я думаю, вы хотите выполнить с рекурсией - обычно использует одни и те же значения каждый раз, но имеет гибкость в изменении некоторых из них. Делает ли это то, что вы хотите?

Ключевым моментом является получение копий ваших аргументов/kwargs, иначе вы будете изменять args/kwargs для каждого неполного вызова в любое время, когда вы что-то измените.

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

def factorial(*args_this_call, **kwargs_this_call): 
    print('-----------------------------' 
      '\nargs: {}' 
      '\nkwargs: {}'.format(args_this_call, kwargs_this_call)) 
    # get copies so you don't modify the values of other calls that are waiting to complete 
    args_next_call = list(args_this_call) 
    kwargs_next_call = kwargs_this_call.copy() 

    # you can break out the content of args/kwargs for clarity if you are going to use them a lot 
    arg1, arg2 = args_this_call # not used - just for example 
    n = kwargs_this_call['n'] 

    # do your work 
    if n == 1: 
     return 1 
    else: 
     # modify whichever args/kwargs you want, leave the ones you don't want to change 
     args_next_call[1] += 1 # some random modification 
     kwargs_next_call['call_id'] += 1 
     kwargs_next_call['n'] -= 1 # n-1 for factorial in this case 

     # make the call 
     result = n * factorial(*args_next_call, **kwargs_next_call) 
     return result 

# test the factorial with args/kwargs 
args = (1, 1) # just some values 
kwargs = {'call_id': 1, 
      'n': 4} 
print(factorial(*args, **kwargs)) 

Результат:

----------------------------- 
args: (1, 1) 
kwargs: {'call_id': 1, 'n': 4} 
----------------------------- 
args: (1, 2) 
kwargs: {'call_id': 2, 'n': 3} 
----------------------------- 
args: (1, 3) 
kwargs: {'call_id': 3, 'n': 2} 
----------------------------- 
args: (1, 4) 
kwargs: {'call_id': 4, 'n': 1} 
24 
Смежные вопросы