2013-03-14 14 views
7

Właśnie zacząłem uczyć się Pythona. Natknąłem się na funkcje lambda. W jednym z problemów autor poprosił o napisanie jednej liniowej funkcji lambda dla silni liczbowej.Pythonowa funkcja lambda do obliczania silni z liczby

Jest to rozwiązanie, które zostało wydane:

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) 

nie mogę zrozumieć składnię dziwne. Co znaczy a (a, b)?

Czy ktoś może wyjaśnić?

Dzięki

+9

mam lepszy: 'lambda b: math.factorial (b)' – JBernardo

+2

Dont narastającymi kwadratowe koło. – ShuklaSannidhya

Odpowiedz

5

jest to prosta:

n=input() 

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

Sam czynnik jest prawie taki, jak można się spodziewać. Wnioskujesz, że a to ... funkcja silni. b jest faktycznym parametrem.

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

Ten bit jest zastosowanie silni:

<factorial-application> = (lambda a, b: a(a, b))(<factorial>, b) 

a jest sama funkcja silnia. Za swój pierwszy argument uważa się, a punkt oceny za drugi. Można to uogólnić na recursive_lambda tak długo, jak nie masz nic a(a, b - 1) zamiast 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)) 

Więc mamy zewnętrzną część:

(lambda b: <factorial-application>)(num) 

Jak widać wszyscy dzwoniący musi przejść jest punkt oceny.


Jeśli faktycznie chciał mieć rekurencyjne lambda, można po prostu name the lambda:

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

Jeśli nie, można użyć a simple helper function. Zauważysz, że ret to lambda, która może odnosić się do siebie, w przeciwieństwie do poprzedniego kodu, w którym żadna lambda nie może się odnosić do siebie.

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 

Oba sposoby nie muszą uciekać się do śmiesznych środków przekazania lambdy samemu sobie.

+0

Aby wyjaśnić: "a" jest przekazywane do siebie? – ApproachingDarknessFish

+0

@ValekHalfHeart Dokładnie. –

+1

To zupełnie nowy poziom pokręconego. – ApproachingDarknessFish

6

Zeskrobmy tę jedną wkładkę otwartą jak cebula.

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

Czynimy anonimową funkcję (lambda słów kluczowych oznacza, że ​​zamiar wpisać serię nazw parametrów, następnie dwukropek, a następnie funkcję, która wykorzystuje te parametry), a następnie przekazać go do zaspokojenia jego num jeden parametr.

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

Wewnątrz lambda definiujemy inną lambdę. Nazwij to lambda Y. Ten przyjmuje dwa parametry, aib. a zostaje wywołany z A i B, a więc jest to, że odbywa się wywoływalny i jeden inny parametr

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

Są to parametry Y. pierwszy jest funkcją lambda nazwać X.Widzimy, że X jest funkcją silni, a drugi parametr stanie się jego numerem.

Oznacza to, że jeśli mamy iść i patrzeć na Y, możemy zobaczyć, że będziemy nazywać:

X(X, b) 

który zrobi

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

i nazywają siebie, tworząc rekurencyjnej część Factorial.

Patrząc całą drogę z powrotem na zewnątrz, widzimy, że b jest liczbą, którą przeszliśmy do najbardziej zewnętrznej lambdy.

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

Jest to rodzaj mylące, ponieważ został napisany jako mylące jeden liner :)

+0

To był konkurs online na jednej liniowej. I przygotowywałem się do tego. To było mylące, ale po spędzeniu dużej ilości czasu, myślę, że to załapałem. Dzięki – suparngp

2

Istnieją dwa twarde części o tej funkcji.
1. lambda a, b: b*a(a, b-1) if b > 0 else 1.
2. "b", który jest folowing 1.

za 1, to nic więcej niż:

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

dla 2, tym 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) 

jest faktycznie to 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) 

Powodem jest to, że nie znajduje się on w definicji drugiej i trzeciej wartości lambda, więc odnosi się do pierwszego b.

Po stosuje NUMER i odpędzenia zewnętrzną funkcję:

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

Po prostu zastosowanie funkcji w krotce, (N a, b: b * a (a, b-1), jeśli B> 0 else 1, num)
Nazwijmy ten krotki jako (f, num) (def f jest powyżej) Stosowanie lambda a, b: a(a, b) na nim, otrzymujemy

f (f, NUM).

Załóżmy, że num to 5.
Przez zaliczane do f, najpierw ocenia się

5 * f(f, 4) 

następnie:

5 * (4 * f(f, 3)) 

całą drogę w dół do

5 * (4 * (3 * (2 * (1 * f(f, 0))))) 

f (f, 0) przechodzi na 1.

5 * (4 * (3 * (2 * (1 * 1)))) 

Tutaj idziemy, silnia 5.

+0

Dzięki @octref. Dałeś jasne wyjaśnienie. – suparngp

1

Możemy użyć poniższego wyrażenia lambda

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

uogólnione def rekurencyjnych lambda jest jak poniżej

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

Bardzo ładnie wyjaśnione! Tylko jeden drobny fix: jeśli b> 1 jeśli nie b> 0

Wynik jest taki sam, ale logicznie bardziej poprawne, ponieważ realizuje jedną niepotrzebną dodatkową pętlę (chociaż mnożąc przez 1)

Wikipedia => N !, jest iloczynem wszystkich dodatnich liczb całkowitych mniejszych lub równych n

Powiązane problemy