2013-03-14 4 views
7

Я только что начал изучать питон. Я наткнулся на лямбда-функции. По одной из проблем автор попросил написать одну линейную лямбда-функцию для факториала числа.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, b)?

Может кто-нибудь объяснить?

Thanks

+9

я лучше один: 'лямбда-B: math.factorial (б)' – JBernardo

+2

Dont изобрести квадратное колесо. – ShuklaSannidhya

ответ

5

Именно это просто:

n=input() 

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

Факториал сам по себе почти так, как вы ожидали. Вы делаете вывод, что 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) 

Как вы видите, все абонент должен пройти это оценка.


Если вы на самом деле хотел иметь рекурсивное лямбда, вы могли бы просто name the lambda:

fact = lambda x: 1 if x == 0 else x * fact(x-1) 

Если нет, то вы можете использовать a simple helper function. Вы заметите, что 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 

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

+0

Чтобы уточнить: 'a' передается самому себе? – ApproachingDarknessFish

+0

@ ValekHalfHeart Точно. –

+1

Это совершенно новый уровень скручивания. – ApproachingDarknessFish

6

Отшелушиваем этот один вкладыш открытым, как лук.

print (lambda b: (Y))(num) 

Мы делаем анонимную функцию (ключевое слово лямбда означает, что мы собираемся ввести ряд имен параметров, затем двоеточие, то функция, которая использует эти параметры), а затем передать его Num, чтобы удовлетворить его один параметр.

(lambda a, b: a(a, b))(X,b) 

Внутри лямбда мы определяем другую лямбду. Назовите эту лямбда Y. Это принимает два параметра: a и b. а называется с а и б, так что является вызываемым, который берет на себя и еще один параметр

  (lambda a, b: b*a(a, b-1) if b > 0 else 1 
      , 
      b) 

Эти параметры, Y. Первый из них является функцией лямбда, назовем его Х.Мы видим, что X - факториальная функция, а второй параметр станет ее числом.

То есть, если мы пойдем и посмотрим на Y, мы можем видеть, что мы будем называть:

X(X, b) 

, который будет делать

b*X(X, b-1) if b > 0 else 1 

и называть себя, формируя рекурсивное часть факториал.

И, взглянув на обратную сторону, мы видим, что b - это число, которое мы перешли в самую внешнюю лямбду.

num*X(X, b-1) if num > 0 else 1 

Это отчасти сбивает с толку, потому что она была написана как запутанным один лайнер :)

+0

Это был онлайн-конкурс на одном лайнере. И я готовился к этому. Это было запутанно, но, проведя много времени, я думаю, что я его сбил. Спасибо – suparngp

2

Есть два жестких частей об этой функции.
1. lambda a, b: b*a(a, b-1) if b > 0 else 1.
2. "Ъ", что это folowing 1.

Для 1, это не более чем:

def f(a, b): 
    if b > 0: 
     b * a(a, b - 1) 
    else: 
     1 

Для 2, это б

(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) 

на самом деле это б:

(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) 

Это просто применение функции к кортежу, (лямбда-а, б: б * а (а, Ь-1), если б> 0 еще 1, Num)
Давайте назовем этот кортеж, как (е, NUM) (DEF F находится выше) Применив lambda a, b: a(a, b) на него, мы получаем

F (F, NUM).

Предположим, что ваш Num 5.
По Definiton Р, сначала вычисляется в

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.

+0

Спасибо @octref. Вы дали ясное объяснение. – suparngp

1

Мы можем использовать ниже лямбда-выражения

 fact = lambda n:1 if n==0 else n*fact(n-1) 
    print(fact(5) 
    >>> 120 
0

обобщенное Защиту рекурсивного лямбда, как показано ниже

recursive_lambda = (lambda func: lambda *args: func(func, *args)) 
0

Очень хорошо объяснил! Только одна незначительная ошибка: если б> 1 НЕ, если б> 0

Результат такой же, но логически более правильным, как он выполняется один ненужный дополнительный цикл (несмотря на то, умножая на 1)

Википедия => п !, это произведение всех натуральных чисел, меньших или равных п

Смежные вопросы