简明扼要地写一个递归函数
DRYly and consisely write a recursive function
我正在编写一个看起来像这样的递归函数:
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()
)
我不想用多余的行来膨胀我的递归调用。解决此问题的最佳方法是什么?
这是我认为您希望通过递归完成的最小示例 - 通常每次都使用相同的值,但可以灵活地更改其中的一些值。这是否符合您的要求?
关键是要获得您的 args/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
考虑使用包装函数来避免重复:
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=
参数。
我正在编写一个看起来像这样的递归函数:
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()
)
我不想用多余的行来膨胀我的递归调用。解决此问题的最佳方法是什么?
这是我认为您希望通过递归完成的最小示例 - 通常每次都使用相同的值,但可以灵活地更改其中的一些值。这是否符合您的要求?
关键是要获得您的 args/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
考虑使用包装函数来避免重复:
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=
参数。