Jaką funkcjonalność functools.partial
oferuje nie można uzyskać przez lambdas?
Niewiele pod względem dodatkowej funkcjonalności (ale zobacz później) - a czytelność zależy od obserwatora.
Większość osób, które są obeznane z funkcjonalnymi językami programowania (szczególnie te z rodzin Lisp / Scheme) wydają się lubić lambda
- mówię „większość”, zdecydowanie nie wszystkie, ponieważ Guido i ja z pewnością należą do osób „zaznajomionych” (itp.) ), ale myślę o lambda
anomalii odleżyn w Pythonie ...
Był skruszony, że kiedykolwiek zaakceptował go w Pythonie, podczas gdy planował usunąć go z Pythona 3, jako jedną z „usterek Pythona”.
W pełni go w tym wspierałem. (Uwielbiam lambda
w Schemacie ... podczas gdy jego ograniczenia w Pythonie i dziwny sposób, że po prostu nie robi resztą języka spraw, by moja skóra czołgała się).
Nie dotyczy to jednak hord lambda
kochanków - którzy zainscenizowali jedną z najbliższych rzeczy buntu, jaką kiedykolwiek widzieliśmy w historii Pythona, dopóki Guido nie wycofał się i nie zdecydował się odejść lambda
.
Kilka możliwych dodatków do functools
(aby funkcje zwracały stałe, tożsamość, itp.) nie nastąpiło (aby uniknąć jawnego powielania większej liczby lambda
funkcji), chociaż partial
oczywiście pozostało (nie jest to całkowite powielanie, ani nie jest odrażeniem).
Pamiętaj, że lambda
ciało jest ograniczone do wyrażania się , więc ma ograniczenia. Na przykład...:
>>> import functools
>>> f = functools.partial(int, base=2)
>>> f.args
()
>>> f.func
<type 'int'>
>>> f.keywords
{'base': 2}
>>>
functools.partial
Zwrócona funkcja jest ozdobiona atrybutami użytecznymi do introspekcji - funkcja ta jest zawijana oraz jakie argumenty pozycyjne i nazwane w niej naprawia. Co więcej, wymienione argumenty można od razu zastąpić („ustalanie” jest raczej w pewnym sensie ustawieniem domyślnym):
>>> f('23', base=10)
23
Tak więc, jak widać, jest to definely nie jest tak proste jak lambda s: int(s, base=2)
! -)
Tak, to mogłoby wykrzywiać swoją lambda dać trochę tego - na przykład dla słowa kluczowego-nadrzędnych,
>>> f = lambda s, **k: int(s, **dict({'base': 2}, **k))
ale mam wielką nadzieję, że nawet najbardziej zagorzały lambda
kochanek nie uważa tego horroru za bardziej czytelny niż partial
wezwanie! -). Część „ustawianie atrybutów” jest jeszcze trudniejsza, ponieważ ograniczenie Pythona do „ciała jest pojedynczym wyrażeniem” lambda
(plus fakt, że przypisanie nigdy nie może być częścią wyrażenia w Pythonie)… w rezultacie „fałszujesz przypisania w wyrażeniu” poprzez rozciągnięcie zrozumienia listy znacznie przekraczając jej granice projektowe ...:
>>> f = [f for f in (lambda f: int(s, base=2),)
if setattr(f, 'keywords', {'base': 2}) is None][0]
Teraz połączyć przeciążania nazwanych argumentów plus ustawienie trzech atrybutów w jednej wypowiedzi, i powiedz mi, w jaki sposób czytelny , że będzie ...!
functools.partial
której wspomniałeś, sprawia, że jest lepsza niż lambda. Być może jest to temat innego postu, ale o co tak bardzo cię martwisz na poziomie projektowanialambda
?def
ilambda
słowa kluczowe: uczyń je obafunction
(wybór jednej nazwy JavaScript jest naprawdę słuszny), a przynajmniej 1/3 moich zastrzeżeń zniknie ! -). Jak powiedziałem, nie mam nic przeciwko lambda w Lisp ...! -)def
. Nasz życzliwy przywódca przemówił!Oto przykład pokazujący różnicę:
Te posty Ivana Moore'a rozwijają „ograniczenia lambda” i zamknięcia w pythonie:
źródło
lambda y, n=n: ...
. Późne wiązanie (imion występujących tylko w ciele funkcji, a nie w jegodef
lub jego odpowiedniklambda
) jest coś , ale to błąd, jak już pokazano na długości w długich odpowiedzi tak w przeszłości: ty wczesnego wiążą się wyraźnie, kiedy to, co chcesz, użyj domyślnego późnego wiązania, gdy tego właśnie chcesz, a to jest dokładnie właściwy wybór projektu, biorąc pod uwagę kontekst reszty projektu Pythona.W najnowszych wersjach Pythona (> = 2.7), można , ale nie :
pickle
partial
lambda
źródło
multiprocessing.Pool.map()
. stackoverflow.com/a/3637905/195139partial
jest dostępny w Pythonie 2.7.Jako częściową odpowiedź na to pytanie postanowiłem przetestować wydajność. Oto mój przykład:
w Pythonie 3.3 daje:
Co oznacza, że częściowe potrzebuje trochę więcej czasu na stworzenie, ale znacznie mniej czasu na wykonanie. Może to być efekt wczesnego i późnego wiązania, które są omówione w odpowiedzi z ars .
źródło
partial
jest napisany w C, a nie w czystym Pythonie, co oznacza, że może produkować bardziej wydajne wywołanie niż tworzenie funkcji wywołującej inną funkcję.Oprócz wspomnianej dodatkowej funkcjonalności Alex, kolejną zaletą funools.partial jest szybkość. Dzięki częściowemu możesz uniknąć konstruowania (i niszczenia) kolejnej ramki stosu.
Ani funkcja generowana przez częściową, ani lambdas nie ma domyślnie ciągów dokumentów (chociaż można ustawić ciąg dokumentów dla dowolnych obiektów przez
__doc__
).Więcej informacji można znaleźć na tym blogu: Aplikacja do funkcji częściowych w języku Python
źródło
Rozumiem cel najszybciej w trzecim przykładzie.
Kiedy parsuję lambdas, oczekuję większej złożoności / osobliwości niż oferowana bezpośrednio przez bibliotekę standardową.
Zauważysz również, że trzeci przykład jest jedynym, który nie zależy od pełnego podpisu
sum2
; dzięki czemu jest nieco luźniej sprzężony.źródło
functools.partial
połączenia zajęło mi dużo więcej czasu , podczas gdy lambda są oczywiste.