Лямбда-функция 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 ответов


Это просто:

n=input()

print reduce(lambda x,y:x*y,range(1,n+1))

давайте очистим этот вкладыш открытым, как лук.

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