Не рекомендуется рекомендовать создание таких функций, как это, но в этом случае, я думаю, лучше иметь статические определения с небольшим дублированием, а не полагаться на динамическую функцию, сложное поведение которой трудно проверить -
def apply_at_1 (f, *a, **kw):
return lambda x, *a2, **kw2: \
f(x, *a, *a2, **kw, **kw2)
def apply_at_2 (f, *a, **kw):
return lambda x, y, *a2, **kw2: \
f(x, y, *a, *a2, **kw, **kw2)
def apply_at_3 (f, *a, **kw):
return lambda x, y, z, *a2, **kw2: \
f(x, y, z, *a, *a2, **kw, **kw2)
def dummy (a, b, c, d, *more):
print (a, b, c, d, *more)
apply_at_1(dummy, 2, 3, 4)(1, 5, 6, 7, 8)
# 1 2 3 4 5 6 7 8
apply_at_2(dummy, 3, 4, 5)(1, 2, 6, 7, 8)
# 1 2 3 4 5 6 7 8
apply_at_3(dummy, 4, 5, 6)(1, 2, 3, 7, 8)
# 1 2 3 4 5 6 7 8
Конечно, динамическая функция позволяет вам применять аргумент в любой позиции, но если вам нужно применить аргумент в четвертой позиции (5-й аргумент), возможно, пришло время рассмотреть рефакторинг. В этом случае я думаю, что лучше установить разумный предел, а затем дисциплинировать себя.
Другие функциональные языки делают схожие вещи по типу ввода. Рассмотрим liftA2
, liftA3
, liftA4
и т.д. у Хаскелла или List.map
, List.map2
, List.map3
, List.map4
, ...
вяза
Иногда поцеловать просто проще.
Вот версия partial
с поддержкой подстановочных знаков, __
-
def __ ():
return None;
def partial (f, *a):
def combine (a, b):
if not a:
return b
elif a[0] is __:
return (b[0], *combine(a[1:], b[1:]))
else:
return (a[0], *combine(a[1:], b))
return lambda *b: f(*combine(a,b))
def dummy (a, b, c, d, *more):
print (a, b, c, d, *more)
partial(dummy, 1, __, __, 4)(2, 3, 5, 6, 7, 8)
# 1 2 3 4 5 6 7 8
partial(dummy, __, __, 3, __, __, 6, 7, 8)(1, 2, 4, 5)
# 1 2 3 4 5 6 7 8