Zawsze używaj instrukcji def zamiast instrukcji przypisania, która wiąże wyrażenie lambda bezpośrednio z nazwą.
Tak:
def f(x):return2*x
Nie:
f =lambda x:2*x
Pierwsza forma oznacza, że nazwą wynikowego obiektu funkcji jest konkretnie „f” zamiast ogólnego „<lambda>”. Jest to bardziej przydatne w przypadku śledzenia wstecznego i reprezentacji ciągów w ogóle. Zastosowanie instrukcji przypisania eliminuje jedyną korzyść, jaką wyrażenie lambda może zaoferować w stosunku do jawnej instrukcji def (tzn. Że można ją osadzić w większym wyrażeniu)
Przypisywanie lambdas do nazw w zasadzie powiela funkcjonalność def- i ogólnie najlepiej zrobić coś w jeden sposób, aby uniknąć nieporozumień i zwiększyć przejrzystość.
Uzasadnionym przypadkiem użycia dla lambda jest miejsce, w którym chcesz użyć funkcji bez przypisania jej, np .:
sorted(players, key=lambda player: player.rank)
Zasadniczo głównym argumentem przeciwko temu jest to, że definstrukcje spowodują powstanie większej liczby wierszy kodu. Moja główna odpowiedź na to brzmi: tak, i jest w porządku. O ile nie grasz w golfa, minimalizowanie liczby linii nie jest czymś, co powinieneś robić: idź na skróty.
Nie rozumiem, jak jest gorzej. Funkcja śledzenia nadal będzie zawierać błędny numer linii i plik źródłowy. Jeden może powiedzieć „f”, a drugi „lambda”. Może błąd lambda jest łatwiejszy do skanowania, ponieważ nie jest to nazwa funkcji jednoznakowej lub źle nazwana długa nazwa?
g33kz0r
4
@ g33kz0r Cóż, oczywiście, jeśli zakładasz, że reszta kodu będzie niskiej jakości, przestrzeganie konwencji nie przyniesie wiele korzyści. Ogólnie rzecz biorąc, nie, to nie koniec świata, ale wciąż jest to zły pomysł.
Gareth Latty
39
Ta odpowiedź nie jest zbyt pomocna, ponieważ po uruchomieniu sugerowanego podejścia polegającego na użyciu defsprawdzania PEP8 otrzymujesz E704 multiple statements on one line (def), a jeśli podzielisz ją na dwie linie, otrzymasz E301 expected 1 blank line, found 0: - /
Adam Spiers
4
Zgadzam się, że powinien zostać podzielony. Chodzi mi o to, że a) nie jest podzielony w powyższym kodzie odpowiedzi, co powoduje E704, i b) jeśli go podzielisz, potrzebujesz brzydkiej pustej linii powyżej, aby uniknąć E301.
Adam Spiers,
3
Używam lambdas, gdy chcę podkreślić czystą funkcję (bez skutków ubocznych), a czasami muszę używać tej samej funkcji w dwóch miejscach, tj. Grupować i sortować razem. Dlatego ignoruję tę konwencję.
manu
119
Oto historia, miałem prostą funkcję lambda, z której korzystałem dwa razy.
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
To tylko dla reprezentacji, spotkałem się z kilkoma różnymi wersjami tego.
Teraz, aby utrzymać stan NA SUCHO, zaczynam ponownie używać tej wspólnej lambda.
f =lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
W tym momencie mój kontroler jakości kodu skarży się, że lambda jest nazwaną funkcją, więc przekształcam ją w funkcję.
def f(x):return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Teraz moduł sprawdzający skarży się, że funkcja musi być ograniczona jedną pustą linią przed i po.
def f(x):return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Tutaj mamy teraz 6 wierszy kodu zamiast oryginalnych 2 wierszy bez zwiększania czytelności i bez zwiększania pythoniczności. W tym momencie narzędzie do sprawdzania kodu skarży się, że funkcja nie ma dokumentów.
Moim zdaniem tej zasady lepiej unikać i łamać, gdy ma to sens, skorzystaj z własnego osądu.
a = [x + offset for x in simple_list]. Nie musisz używać mapi lambdatutaj.
Georgy,
8
@Georgy Myślę, że chodziło o przeniesienie x + offsetczęści do abstrakcyjnej lokalizacji, którą można zaktualizować bez zmiany więcej niż jednego wiersza kodu. Z listami, które już wspomniałeś, nadal potrzebujesz dwóch linii kodu, które zawierałyby x + offsetje teraz w listach. Aby wyciągnąć je tak, jak chciał autor, potrzebujesz deflub lambda.
Julian
1
@Julian Oprócz defi lambdamożna również użyć funools.partial : f = partial(operator.add, offset)a następnie a = list(map(f, simple_list)).
Georgy,
Co z def f(x): return x + offset(tj. Prostą funkcją zdefiniowaną w jednym wierszu)? Przynajmniej z flake8 nie otrzymuję skarg na puste linie.
DocOc,
1
@Julian W niektórych przypadkach możesz użyć zagnieżdżonego rozumienia:a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
wjandrea
24
Lattyware ma absolutną rację: Zasadniczo PEP-8 chce, abyś unikał takich rzeczy
f =lambda x:2* x
i zamiast tego użyj
def f(x):return2* x
Jednak, jak opisano w ostatnim raporcie o błędach (sierpień 2014 r.), Następujące oświadczenia są teraz zgodne:
a.f =lambda x:2* x
a["f"]=lambda x:2* x
Ponieważ mój moduł sprawdzania PEP-8 jeszcze tego nie implementuje, na razie wyłączyłem E731.
Nawet podczas używania defmoduł sprawdzania PEP8 narzeka E301 expected 1 blank line, found 0, więc musisz dodać brzydką pustą linię przed nim.
Adam Spiers,
1
Zetknąłem się również z sytuacją, w której korzystanie z funkcji def (ined) było niemożliwe.
classSomeClass(object):# pep-8 does not allow this
f =lambda x: x +1# NOQAdef not_reachable(self, x):return x +1@staticmethoddef also_not_reachable(x):return x +1@classmethoddef also_not_reachable(cls, x):return x +1
some_mapping ={'object1':{'name':"Object 1",'func': f},'object2':{'name':"Object 2",'func': some_other_func},}
W tym przypadku naprawdę chciałem stworzyć mapowanie należące do klasy. Niektóre obiekty w mapowaniu wymagały tej samej funkcji. Nielogiczne byłoby umieszczanie nazwanej funkcji poza klasą. Nie znalazłem sposobu na odwołanie się do metody (metoda statyczna, metoda klasowa lub normalna) z wnętrza klasy. SomeClass jeszcze nie istnieje po uruchomieniu kodu. Odwołanie się do tego z klasy też nie jest możliwe.
Można zapoznać się also_not_reachablew definicji mapowania jakoSomeClass.also_not_reachable
yaccz
1
Nie wiem, o co tu chodzi. Każda nazwa twojej funkcji jest fdla mnie tak dostępna, jak w wersjach 2.7 i 3.5
Eric
Nie, wszystkie funkcje, z wyjątkiem funkcji lambda, nie są osiągalne z wnętrza klasy. Otrzymasz AttributeError: typ obiektu „SomeClass” nie ma atrybutu „...”, jeśli spróbujesz uzyskać dostęp do jednej z tych funkcji w obiekcie some_mapping.
simP
3
@simP wszystkie są doskonale dostępne. Te z @staticmethodi @classmethodnie potrzebują obiektu, tylko SomeClass.also_not_reachable(chociaż potrzebują charakterystycznych nazw). Jeśli chcesz uzyskać do nich dostęp metodami klasowymi, po prostu użyjself.also_not_reachable
ababak
@simP może powinieneś zmienić nazwę swojego *not_reachable metod na not_as_easily_reachable_from_class_definition_as_a_lambdaxD
flake8
( flake8.pycqa.org )Odpowiedzi:
Zalecenia w PEP-8, na które się napotykasz, to:
Przypisywanie lambdas do nazw w zasadzie powiela funkcjonalność
def
- i ogólnie najlepiej zrobić coś w jeden sposób, aby uniknąć nieporozumień i zwiększyć przejrzystość.Uzasadnionym przypadkiem użycia dla lambda jest miejsce, w którym chcesz użyć funkcji bez przypisania jej, np .:
Zasadniczo głównym argumentem przeciwko temu jest to, że
def
instrukcje spowodują powstanie większej liczby wierszy kodu. Moja główna odpowiedź na to brzmi: tak, i jest w porządku. O ile nie grasz w golfa, minimalizowanie liczby linii nie jest czymś, co powinieneś robić: idź na skróty.źródło
def
sprawdzania PEP8 otrzymujeszE704 multiple statements on one line (def)
, a jeśli podzielisz ją na dwie linie, otrzymaszE301 expected 1 blank line, found 0
: - /Oto historia, miałem prostą funkcję lambda, z której korzystałem dwa razy.
To tylko dla reprezentacji, spotkałem się z kilkoma różnymi wersjami tego.
Teraz, aby utrzymać stan NA SUCHO, zaczynam ponownie używać tej wspólnej lambda.
W tym momencie mój kontroler jakości kodu skarży się, że lambda jest nazwaną funkcją, więc przekształcam ją w funkcję.
Teraz moduł sprawdzający skarży się, że funkcja musi być ograniczona jedną pustą linią przed i po.
Tutaj mamy teraz 6 wierszy kodu zamiast oryginalnych 2 wierszy bez zwiększania czytelności i bez zwiększania pythoniczności. W tym momencie narzędzie do sprawdzania kodu skarży się, że funkcja nie ma dokumentów.
Moim zdaniem tej zasady lepiej unikać i łamać, gdy ma to sens, skorzystaj z własnego osądu.
źródło
a = [x + offset for x in simple_list]
. Nie musisz używaćmap
ilambda
tutaj.x + offset
części do abstrakcyjnej lokalizacji, którą można zaktualizować bez zmiany więcej niż jednego wiersza kodu. Z listami, które już wspomniałeś, nadal potrzebujesz dwóch linii kodu, które zawierałybyx + offset
je teraz w listach. Aby wyciągnąć je tak, jak chciał autor, potrzebujeszdef
lublambda
.def
ilambda
można również użyć funools.partial :f = partial(operator.add, offset)
a następniea = list(map(f, simple_list))
.def f(x): return x + offset
(tj. Prostą funkcją zdefiniowaną w jednym wierszu)? Przynajmniej z flake8 nie otrzymuję skarg na puste linie.a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware ma absolutną rację: Zasadniczo PEP-8 chce, abyś unikał takich rzeczy
i zamiast tego użyj
Jednak, jak opisano w ostatnim raporcie o błędach (sierpień 2014 r.), Następujące oświadczenia są teraz zgodne:
Ponieważ mój moduł sprawdzania PEP-8 jeszcze tego nie implementuje, na razie wyłączyłem E731.
źródło
def
moduł sprawdzania PEP8 narzekaE301 expected 1 blank line, found 0
, więc musisz dodać brzydką pustą linię przed nim.Zetknąłem się również z sytuacją, w której korzystanie z funkcji def (ined) było niemożliwe.
W tym przypadku naprawdę chciałem stworzyć mapowanie należące do klasy. Niektóre obiekty w mapowaniu wymagały tej samej funkcji. Nielogiczne byłoby umieszczanie nazwanej funkcji poza klasą. Nie znalazłem sposobu na odwołanie się do metody (metoda statyczna, metoda klasowa lub normalna) z wnętrza klasy. SomeClass jeszcze nie istnieje po uruchomieniu kodu. Odwołanie się do tego z klasy też nie jest możliwe.
źródło
also_not_reachable
w definicji mapowania jakoSomeClass.also_not_reachable
f
dla mnie tak dostępna, jak w wersjach 2.7 i 3.5@staticmethod
i@classmethod
nie potrzebują obiektu, tylkoSomeClass.also_not_reachable
(chociaż potrzebują charakterystycznych nazw). Jeśli chcesz uzyskać do nich dostęp metodami klasowymi, po prostu użyjself.also_not_reachable
*not_reachable
metod nanot_as_easily_reachable_from_class_definition_as_a_lambda
xD