Jestem pewien, że istnieje prostszy sposób na zrobienie tego, co po prostu mi się nie zdarza.
Nazywam wiele metod, które zwracają listę. Lista może być pusta. Jeśli lista nie jest pusta, chcę zwrócić pierwszą pozycję; w przeciwnym razie chcę zwrócić Brak. Ten kod działa:
my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None
Wydaje mi się, że powinien istnieć prosty, jednowierszowy idiom do zrobienia tego, ale przez całe życie nie mogę o tym myśleć. Jest tu?
Edytować:
Powodem, dla którego szukam tutaj wyrażenia jednowierszowego, nie jest to, że lubię niewiarygodnie zwięzły kod, ale dlatego, że muszę napisać dużo takiego kodu:
x = get_first_list()
if x:
# do something with x[0]
# inevitably forget the [0] part, and have a bug to fix
y = get_second_list()
if y:
# do something with y[0]
# inevitably forget the [0] part AGAIN, and have another bug to fix
To, co chciałbym robić, z pewnością można osiągnąć za pomocą funkcji (i prawdopodobnie będzie):
def first_item(list_or_none):
if list_or_none: return list_or_none[0]
x = first_item(get_first_list())
if x:
# do something with x
y = first_item(get_second_list())
if y:
# do something with y
Zadałem pytanie, ponieważ często jestem zaskoczony tym, co potrafią proste wyrażenia w Pythonie, i pomyślałem, że napisanie funkcji było głupią rzeczą, gdyby istniało proste wyrażenie. Ale widząc te odpowiedzi, wydaje się, że funkcja jest prostym rozwiązaniem.
źródło
next(iter(your_list), None)
zamiastfirst_item(your_list)
zakładać, żeyour_list
nieNone
(get_first_list()
iget_second_list()
zawsze musi zwrócić iterowalną).next(iter(your_list))
, ponieważ jeśli podasz drugi argumentiter
, mówisz mu, że pierwszy argument jest możliwy do wywołania.None
tutaj jest drugi parametr dlanext()
, nieiter()
.next()
zwraca drugi parametr, jeśli podano, zamiast podnoszenia,StopIteration
jeśliyour_list
jest pusty.Odpowiedzi:
Python 2.6+
Jeśli
your_list
może byćNone
:Python 2.4
Przykład:
Inną opcją jest wstawienie powyższej funkcji:
Aby tego uniknąć,
break
możesz napisać:Gdzie:
źródło
""
na liście znajduje się pusty ciąg , jest on odrzucany i zastępowany pustą listą[]
. Jeśli masz 0, również zastąpione przez[]
. Jeśli maszFalse
tam, również wymienione. Itd. Możesz uciec od tego w konkretnym przypadku, ale jest to zły nawyk do rozwijania się.bool(lst)
mówi nam, czylen(lst) > 0
nie mówi nam nic o tym, colst
zawiera, np.bool([False]) == True;
dlatego wyrażenie[False] or []
zwraca[False]
, to samo dotyczy[0] or []
zwrotu[0]
.yield_first()
aby uniknąćbreak
oświadczenia.Najlepszy sposób to:
Możesz także zrobić to w jednym wierszu, ale programiście jest o wiele trudniej odczytać:
źródło
next(iter(your_list), None)
next(iter(your_list))
wystarczyNone
jak prosi OP. Spróbuj:next(iter([]))
.To powinno działać.
BTW Nie użyłem zmiennej
list
, ponieważ to zastępuje wbudowanąlist()
funkcję.Edycja: Miałem wcześniej nieco prostszą, ale złą wersję.
źródło
Najbardziej idiomatycznym sposobem Pythona jest użycie funkcji next () w iteratorze, ponieważ lista jest iterowalna . dokładnie tak, jak @JFSebastian w komentarzu z 13 grudnia 2011 r.
next(iter(the_list), None)
Zwraca Brak, jeślithe_list
jest pusty. zobacz next () Python 2.6+lub jeśli wiesz na pewno
the_list
nie jest pusty:iter(the_list).next()
zobacz iterator.next () Python 2.2+źródło
return l[0] if l else None
gdyby lista była libcomp. Kiedy lista faktycznie jest genexpr, jest to nawet lepsze, ponieważ nie musisz budować całej listy jak wnext(iter(x for x in range(10) if x % 2 == 0), None)
the_list
nie jest pusty, napiszeszthe_list[0]
.Jeśli próbujesz wyciągnąć pierwszą rzecz (lub brak) ze zrozumienia listy, możesz przełączyć się na generator, aby to zrobić w następujący sposób:
Pro: działa, jeśli bla nie jest indeksowalny Con: to nieznana składnia. Jest to przydatne podczas hakowania i filtrowania rzeczy w ipython.
źródło
Rozwiązanie OP jest już blisko, jest tylko kilka rzeczy, aby uczynić go bardziej Pythonic.
Po pierwsze, nie ma potrzeby uzyskiwania długości listy. Puste listy w Pythonie oceniają na False w czeku if. Po prostu powiedz
Dodatkowo przypisywanie zmiennych zmiennych nakładających się na słowa zastrzeżone jest bardzo złym pomysłem. „lista” jest słowem zastrzeżonym w języku Python.
Zmieńmy to na
Naprawdę ważną kwestią, której brakuje wielu rozwiązaniom, jest to, że wszystkie funkcje / metody Pythona domyślnie zwracają Brak . Spróbuj wykonać poniższe czynności.
O ile nie musisz zwracać None, aby wcześniej zakończyć działanie funkcji, nie jest konieczne jawne zwracanie None. Zupełnie zwięźle, po prostu zwróć pierwszy wpis, jeśli istnieje.
I na koniec, być może zostało to dorozumiane, ale żeby być jawnym (ponieważ jawne jest lepsze niż niejawne ), nie powinieneś mieć swojej funkcji, aby pobierała listę z innej funkcji; po prostu przekaż to jako parametr. Tak więc końcowy wynik byłby
Jak powiedziałem, OP już prawie się pojawił, a zaledwie kilka dotknięć nadaje mu smak Pythona, którego szukasz.
źródło
get_first_item
powinien zaakceptowaćdefault
parametr (jakdict.get
), który domyślnie przyjmuje wartość Brak. W ten sposób interfejs funkcji wyraźnie komunikuje, co się stanie, jeślimy_list
będzie pusty.źródło
Szczerze mówiąc, nie sądzę, aby istniał lepszy idiom: twój jest jasny i zwięzły - nie potrzebujesz niczego „lepszego”. Być może, ale to naprawdę kwestia gustu, którą możesz zmienić za
if len(list) > 0:
pomocąif list:
- pusta lista zawsze będzie oznaczać False.W pokrewnej notatce Python nie jest Perlem (nie ma sensu!), Nie musisz uzyskiwać najfajniejszego możliwego kodu.
W rzeczywistości najgorszy kod, jaki widziałem w Pythonie, był również bardzo fajny :-) i całkowicie niemożliwy do utrzymania.
Nawiasem mówiąc, większość rozwiązań, które tu widziałem, nie biorą pod uwagę, gdy lista [0] ma wartość False (np. Pusty ciąg znaków lub zero) - w tym przypadku wszystkie zwracają None i niewłaściwy element.
źródło
if lst:
zamiastif len(lst) > 0:
. Nie używaj też słów kluczowych Python jako nazw zmiennych; kończy się we łzach. Często stosuje sięL
lublst
jako nazwę zmiennej dla niektórych list. Jestem pewien, że w tym przypadku nie miałeś zamiaru sugerować używanialist
nazwy zmiennej, po prostu miałeś na myśli „jakąś listę”. I +1 dla „kiedy lst [0] ocenia na False”.Najbardziej pytoniczne podejście jest tym, co wykazała najbardziej pozytywna odpowiedź, i po raz pierwszy przyszło mi do głowy, gdy czytam pytanie. Oto jak go użyć, po pierwsze, jeśli ewentualnie pusta lista zostanie przekazana do funkcji:
A jeśli lista zostanie zwrócona z
get_list
funkcji:Wykazano, że można to zrobić tutaj w inny sposób, wraz z objaśnieniami
for
Kiedy zacząłem wymyślać sprytne sposoby na zrobienie tego, to druga rzecz, o której pomyślałem:
Zakłada się, że funkcja kończy się tutaj, domyślnie zwraca,
None
jeśliget_list
zwraca pustą listę. Poniższy jawny kod jest dokładnie równoważny:if some_list
Zaproponowano również następujące (poprawiłem niepoprawną nazwę zmiennej), która również korzysta z niejawnej
None
. Byłoby to lepsze niż powyższe, ponieważ wykorzystuje sprawdzanie logiczne zamiast iteracji, która może się nie zdarzyć. Powinno to być łatwiejsze do natychmiastowego zrozumienia, co się dzieje. Ale jeśli piszemy dla czytelności i łatwości konserwacji, powinniśmy również dodaćreturn None
na końcu wyraźne :pokroić
or [None]
i wybrać indeks zerowyTen jest również w najczęściej głosowanej odpowiedzi:
Wycinek jest niepotrzebny i tworzy w pamięci dodatkową listę z jednym elementem. Następujące powinny być bardziej wydajne. Aby to wyjaśnić,
or
zwraca drugi element, jeśli pierwszy znajduje sięFalse
w kontekście logicznym, więc jeśliget_list
zwróci pustą listę, wyrażenie zawarte w nawiasach zwróci listę z „Brak”, do której dostęp uzyska następnie0
indeks:Następny wykorzystuje fakt, że zwraca drugi element, jeśli pierwszy jest
True
w kontekście logicznym, a ponieważ dwukrotnie odwołuje się do mojej_listy, nie jest lepszy niż wyrażenie trójkowe (i technicznie nie jest to jednowierszowy):next
Następnie mamy następujące sprytne użycie wbudowanego
next
iiter
Aby wyjaśnić,
iter
zwraca iterator z.next
metodą. (.__next__
W Pythonie 3.), a następnie wbudowanenext
połączenia, które.next
metody, a jeśli iterator jest wyczerpany, przywraca domyślne dajemy,None
.redundantne wyrażenie trójskładnikowe (
a if b else c
) i krążące w tyłZaproponowano poniżej, ale odwrotność byłaby lepsza, ponieważ logika jest zwykle lepiej rozumiana w pozytywnych zamiast negatywnych. Ponieważ
get_list
jest wywoływany dwukrotnie, chyba że wynik zostanie w jakiś sposób zapamiętany, to działałoby to źle:Im lepsza odwrotność:
Co więcej, użyj zmiennej lokalnej, która
get_list
jest wywoływana tylko raz, i najpierw omówiono zalecane rozwiązanie w języku Python:źródło
Jeśli chodzi o idiomy, istnieje przepis itertools o nazwie
nth
.Z przepisów itertools:
Jeśli chcesz mieć jeden wiersz, rozważ zainstalowanie biblioteki, która implementuje ten przepis dla Ciebie, np .
more_itertools
:Dostępne jest inne narzędzie, które zwraca tylko pierwszy element o nazwie
more_itertools.first
.Te narzędzia itertools są skalowane ogólnie dla dowolnej iteracji, nie tylko dla list.
źródło
my_list[0] if len(my_list) else None
źródło
len
bez powodu. Jeśli miałbyś go usunąć, powyższy kod zrobiłby to samo.Z ciekawości sprawdziłem czasy dwóch rozwiązań. Rozwiązanie wykorzystujące instrukcję return do przedwczesnego zakończenia pętli for jest nieco droższe na moim komputerze z Pythonem 2.5.1. Podejrzewam, że ma to związek z konfiguracją iterowalności.
Oto czasy, które otrzymałem:
źródło
źródło
if len(a) > 0:
ale jest to uważane za dobry styl. Zwróć uwagę, jak dobrze to wyraża problem: „spróbuj wyodrębnić nagłówek listy, a jeśli to nie zadziała, wróćNone
”. Wyszukaj w Google „EAFP” lub spójrz tutaj: python.net/~goodger/projects/pycon/2007/idiomatic/…BTW: Chciałbym przerobić ogólny przebieg programu na coś takiego:
(Unikanie powtarzania, gdy tylko jest to możliwe)
źródło
Co powiesz na to:
(my_list and my_list[0]) or None
Uwaga: Powinno to działać poprawnie w przypadku list obiektów, ale może zwrócić niepoprawną odpowiedź w przypadku listy liczb lub ciągów w komentarzach poniżej.
źródło
([0,1] and 0) or None
!(['','A'] and '') or None
.my_list[0]
zostanie ocenione jakoFalse
, wynik powinien byćNone
.my_list[0] if len(my_list) else None
Nie jestem pewien, jak to jest pythonowe, ale dopóki nie pojawi się pierwsza funkcja w bibliotece, dołączam to do źródła:
To tylko jedna linia (odpowiada czerni) i pozwala uniknąć zależności.
źródło
Za pomocą sztuczki i-lub:
źródło
Prawdopodobnie nie jest to najszybsze rozwiązanie, ale nikt nie wspomniał o tej opcji:
jeśli
get_list()
możesz wrócićNone
, możesz użyć:Zalety:
-jedna linia
- zadzwoń tylko
get_list()
raz-łatwy do zrozumienia
źródło
Mój przypadek użycia polegał jedynie na ustawieniu wartości zmiennej lokalnej.
Osobiście znalazłem próbę i oprócz czyszczenia stylu do przeczytania
niż krojenie listy.
źródło
Kilka osób zasugerowało zrobienie czegoś takiego:
Działa to w wielu przypadkach, ale zadziała tylko wtedy, gdy lista [0] nie jest równa 0, False lub pusty ciąg znaków. Jeśli lista [0] ma wartość 0, Fałsz lub pusty ciąg znaków, metoda niepoprawnie zwróci Brak.
źródło
Możesz użyć metody wyodrębnienia . Innymi słowy, wypakuj ten kod do metody, którą następnie wywołasz.
Nie próbowałbym go bardziej kompresować, te linijki wydają się trudniejsze do odczytania niż wersja pełna. A jeśli użyjesz metody ekstrakcji, jest to jedna linijka;)
źródło
źródło
nie jest idiomatycznym pytonem równoważnym do operatorów trójskładnikowych w stylu C.
to znaczy.
źródło