Zanurkuj w Pythonie/Wyrażenia lambda
Wyrażenia lambda
[edytuj]Python za pomocą pewnych wyrażeń pozwala nam zdefiniować jednolinijkowe mini-funkcje. Te tzw. funkcje lambda
są zapożyczone z Lispa i mogą być użyte wszędzie tam, gdzie potrzebna jest funkcja.
lambda
>>> def f(x): ... return x*2 ... >>> f(3) 6 >>> g = lambda x: x*2 #(1) >>> g(3) 6 >>> (lambda x: x*2)(3) #(2) 6
- W ten sposób tworzymy funkcję
lambda
, która daje ten sam efekt jak normalna funkcja nad nią. Zwróćmy uwagę na skróconą składnię: nie ma nawiasów wokół listy argumentów, brakuje też słowa kluczowegoreturn
(cała funkcja może być tylko jednym wyrażeniem). Funkcja nie posiada również nazwy, ale może być wywołana za pomocą zmiennej, do której zostanie przypisana. - Możemy użyć funkcji
lambda
bez przypisywania jej do zmiennej. Może taki sposób korzystania z wyrażeńlambda
nie jest zbyt przydatny, ale w ten sposób możemy zobaczyć, że za pomocą tego wyrażenia tworzymy funkcję jednolinijkową.
Podsumowując, funkcja lambda
jest funkcją, która pobiera dowolną liczbę argumentów (włączając argumenty opcjonalne) i zwraca wartość, którą otrzymujemy po wykonaniu pojedynczego wyrażenia. Funkcje lambda
nie mogą zawierać poleceń i nie mogą zawierać więcej niż jednego wyrażenia. Nie próbujmy upchać zbyt dużo w funkcję lambda
; zamiast tego jeśli potrzebujemy coś bardziej złożonego, zdefiniujmy normalną funkcję.
Korzystanie z wyrażeń lambda zależy od stylu programowania. Używanie ich nigdy nie jest wymagane; wszędzie gdzie moglibyśmy z nich skorzystać, równie dobrze moglibyśmy zdefiniować oddzielną, normalną funkcję i użyć jej zamiast funkcji lambda . Funkcje lambda możemy używać np. w miejscach, w których potrzebujemy specyficznego, nieużywalnego powtórnie kodu. Dzięki temu nie zaśmiecamy kodu wieloma małymi jednoliniowymi funkcjami.
|
Funkcje lambda
w prawdziwym świecie
[edytuj]Poniżej przedstawiamy funkcje lambda
wykorzystaną w apihelper.py:
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
Zauważmy, że użyta jest tu prosta forma sztuczki and
-or
, która jest bezpieczna, ponieważ funkcja lambda
jest zawsze prawdą w kontekście logicznym. (To nie znaczy, że funkcja lambda nie może zwracać wartości będącej fałszem. Funkcja jest zawsze prawdą w kontekście logicznym, ale jej zwracana wartość może być czymkolwiek.)
Zauważmy również, że używamy funkcji split
bez argumentów. Widzieliśmy już ją użytą z jednym lub dwoma argumentami. Jeśli nie podamy argumentów, wówczas domyślnym separatorem tej funkcji są białe znaki (czyli spacja, znak nowej linii, znak tabulacji itp.).
split
bez argumentów
>>> s = "this is\na\ttest" #(1) >>> print s this is a test >>> print s.split() #(2) ['this', 'is', 'a', 'test'] >>> print " ".join(s.split()) #(3) 'this is a test'
- Tutaj mamy wieloliniowy napis, zdefiniowany przy pomocy znaków sterujących zamiast użycia trzykrotnych cudzysłowów. \n jest znakiem nowej linii, a \t znakiem tabulacji.
- split bez żadnych argumentów dzieli na białych znakach, a trzy spacje, znak nowej linii i znak tabulacji są białymi znakami.
- Możemy unormować białe znaki poprzez podzielenie napisu za pomocą metody
split
, a potem powtórne złączenie metodąjoin
, używając pojedynczej spacji jako separatora. To właśnie robi funkcjainfo
, aby zwinąć wieloliniowe notki dokumentacyjne w jedną linię.
Co więc właściwie funkcja info
robi z tymi funkcjami lambda
, dzieleniami i sztuczkami and
-or
?
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
processFunc
jest teraz referencją do funkcji, ale zależną od zmiennej collapse
. Jeśli collapse
jest prawdą, processFunc(string)
będzie zwijać białe znaki, a w przeciwnym wypadku processFunc(string)
zwróci swój argument niezmieniony.
Aby to zrobić w mniej zaawansowanym języku (np. w Visual Basicu), prawdopodobnie stworzylibyśmy funkcję, która pobiera napis oraz argument collapse
i używa instrukcji if
, aby określić czy zawijać białe znaki czy też nie, a potem zwracałaby odpowiednią wartość. Takie podejście nie byłoby zbyt efektywne, ponieważ funkcja musiałaby obsłużyć każdy możliwy przypadek. Za każdym jej wywołaniem, musiałaby zdecydować czy zawijać białe znaki zanim dałaby nam to, co chcemy. W Pythonie logikę wyboru możemy wyprowadzić poza funkcję i zdefiniować funkcję lambda
, która jest dostosowana do tego, aby dać nam dokładnie to (i tylko to), co chcemy. Takie podejście jest bardziej efektywne, bardziej eleganckie i mniej podatne na błędy typu "Ups! Te argumenty miały być w odwrotnej kolejności...".