Лямбда-функция Python для вычисления факториала числа
Я только начал изучать python. Я наткнулся на лямбда-функции. По одной из проблем автор попросил написать однострочную лямбда-функцию для факториала числа.
Это решение, которое было дано:
num = 5
print (lambda b: (lambda a, b: a(a, b))(lambda a, b: b*a(a, b-1) if b > 0 else 1,b))(num)
Я не могу понять странный синтаксис. Что означает a(a,b)?
может кто-нибудь объяснить?
спасибо
7 ответов
давайте очистим этот вкладыш открытым, как лук.
print (lambda b: (Y))(num)
мы создаем анонимную функцию (ключевое слово lambda означает, что мы собираемся ввести ряд имен параметров, затем двоеточие, затем функцию, которая использует эти параметры), а затем передаем ее num для удовлетворения ее одного параметра.
(lambda a, b: a(a, b))(X,b)
внутри лямбды мы определяем другую лямбду. Назовите это лямбда Y. Это принимает два параметра, a и b. a вызывается с a и b, поэтому A является вызываемым, который принимает сам и еще один параметр
(lambda a, b: b*a(a, b-1) if b > 0 else 1
,
b)
это параметры для Y. первый из них является лямбда-функцией, назовите его X. Мы видим, что X является факториальной функцией, и что второй параметр станет ее номером.
то есть, если мы поднимемся и посмотрим на Y, мы увидим, что мы позвоним:
X(X, b)
что будет делать
b*X(X, b-1) if b > 0 else 1
и назовите себя, образуя рекурсивную часть факториала.
и смотреть весь путь назад снаружи, мы видим, что b-это num, который мы перешли во внешнюю лямбду.
num*X(X, b-1) if num > 0 else 1
это немного запутанно, потому что он был написан как запутанный один лайнер:)
сам факториал почти такой, как вы ожидали. Вы предполагаете, что a
есть... факториальная функция. b
является фактическим параметром.
<factorial> = lambda a, b: b*a(a, b-1) if b > 0 else 1
этот бит является применением факториала:
<factorial-application> = (lambda a, b: a(a, b))(<factorial>, b)
a
сама факториальная функция. Он берет себя в качестве первого аргумента, а оценку-в качестве второго. Это можно обобщить на recursive_lambda
до тех пор, пока вы не возражаете a(a, b - 1)
вместо a(b - 1)
:
recursive_lambda = (lambda func: lambda *args: func(func, *args))
print(recursive_lambda(lambda self, x: x * self(self, x - 1) if x > 0 else 1)(6))
# Or, using the function verbatim:
print(recursive_lambda(lambda a, b: b*a(a, b-1) if b > 0 else 1)(6))
Итак, у нас есть внешняя часть:
(lambda b: <factorial-application>)(num)
как вы видите, все вызывающий должен пройти точку оценки.
если вы на самом деле хотел иметь рекурсивную лямбду, вы могли бы просто название лямбда:
fact = lambda x: 1 if x == 0 else x * fact(x-1)
если нет, вы можете использовать простая вспомогательная функция. Вы заметите, что ret
- это лямбда, которая может ссылаться на себя, в отличие от предыдущего кода там, где ни одна лямбда не могла сослаться на себя.
def recursive_lambda(func):
def ret(*args):
return func(ret, *args)
return ret
print(recursive_lambda(lambda factorial, x: x * factorial(x - 1) if x > 1 else 1)(6)) # 720
в обоих случаях вам не нужно прибегать к нелепым средствам передачи лямбды самой себе.
есть две жесткие части об этой функции.
1. lambda a, b: b*a(a, b-1) if b > 0 else 1
.
2. буква "Б", следующая за первой.
для 1, это не более чем:
def f(a, b):
if b > 0:
b * a(a, b - 1)
else:
1
для 2, это b
(lambda b: (lambda a, b: a(a, b))(lambda a, b: b*a(a, b-1) if b > 0 else 1,b))(num)
(this one)
на самом деле это B:
(lambda b: (lambda a, b: a(a, b))(lambda a, b: b*a(a, b-1) if b > 0 else 1,b))(num)
(this one)
причина в том, что он не находится внутри определения второй и третьей лямбды, поэтому он относится к первому b.
после того как мы прикладываем num и обнажаем наружное функция:
(lambda a, b: a(a, b)) (lambda a, b: b*a(a, b-1) if b > 0 else 1, num)
это просто применение функции к кортежу, (лямбда a, b: b*a (a, b-1), Если b > 0 еще 1, num)
Назовем этот кортеж как (f, num) (f's def выше)
Применение lambda a, b: a(a, b)
на нем, мы получим
f (f, num).
предположим, что ваш num равен 5.
По определению f, он сначала оценивает
5 * f(f, 4)
затем:
5 * (4 * f(f, 3))
вплоть до
5 * (4 * (3 * (2 * (1 * f(f, 0)))))
f (f, 0) идет к 1.
5 * (4 * (3 * (2 * (1 * 1))))
вот мы идем, факториал 5.
мы можем использовать ниже лямбда-выражение
fact = lambda n:1 if n==0 else n*fact(n-1)
print(fact(5)
>>> 120
обобщенный def рекурсивной лямбды, как показано ниже
recursive_lambda = (lambda func: lambda *args: func(func, *args))
очень хорошо объяснено! Только одно незначительное исправление: если b > 1 нет, если b > 0
результат тот же, но логически более правильный, поскольку он выполняет один ненужный дополнительный цикл (даже при умножении на 1)
Википедия => n!, является произведением всех положительных целых чисел меньше или равно n