Idiom Pythona zwracający pierwszą pozycję lub brak
Jestem pewien, że jest prostszy sposób na zrobienie tego, co nie przychodzi mi do głowy.
Wywołuję kilka metod, które zwracają listę. Lista może być pusta. Jeśli lista nie jest pusta, chcę zwrócić pierwszy element; w przeciwnym razie chcę zwrócić żaden. 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 idiom jednolinijkowy, ale nie mogę o tym myśleć. Naprawdę?
Edit:
The reason that I ' m szukając tu wyrażenia jednowierszowego nie jest tak, że lubię niesamowicie 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
Wysłałem pytanie, ponieważ często jestem zaskoczony tym, co proste wyrażenia w Pythonie mogą zrobić, i pomyślałem, że pisanie funkcji było Głupotą, jeśli istnieje proste wyrażenie może zrobić trik. Ale widząc te odpowiedzi, wydaje się, że funkcja jest prostym rozwiązaniem.
23 answers
Python 2.6 +
next(iter(your_list), None)
Jeśli your_list
może być None
:
next(iter(your_list or []), None)
Python 2.4
def get_first(iterable, default=None):
if iterable:
for item in iterable:
return item
return default
Przykład:
x = get_first(get_first_list())
if x:
...
y = get_first(get_second_list())
if y:
...
Inną opcją jest wbudowanie powyższej funkcji:
for x in get_first_list() or []:
# process x
break # process at most one item
for y in get_second_list() or []:
# process y
break
Aby uniknąć break
możesz napisać:
for x in yield_first(get_first_list()):
x # process x
for y in yield_first(get_second_list()):
y # process y
Gdzie:
def yield_first(iterable):
for item in iterable or []:
yield item
return
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-23 11:45:10
Najlepszy sposób jest taki:
a = get_list()
return a[0] if a else None
Można też zrobić to w jednej linijce, ale programiście jest o wiele trudniej czytać:
return (get_list()[:1] or [None])[0]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 20:12:27
(get_list() or [None])[0]
To powinno zadziałać.
BTW nie użyłem zmiennej list
, ponieważ to nadpisuje wbudowaną funkcję list()
.
Edit: miałem nieco prostszą, ale błędną wersję tutaj wcześniej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-08 15:15:17
Najbardziej idiomatycznym sposobem Pythona jest użycie next () na iteratorze, ponieważ list jest iterable . tak jak @J. F. Sebastian dodał komentarz 13 grudnia 2011.
next(iter(the_list), None)
zwraca None, Jeśli the_list
jest puste. 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+
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-20 06:36:29
Rozwiązanie OP jest prawie gotowe, jest tylko kilka rzeczy, które sprawią, że będzie bardziej Pythoniczne.
Po pierwsze, nie ma potrzeby, aby uzyskać długość listy. Puste listy w Pythonie oceniają na False w sprawdzeniu if. Po prostu powiedz
if list:
Dodatkowo, bardzo złym pomysłem jest przypisywanie zmiennych, które nakładają się na słowa zarezerwowane. "lista" jest słowem zastrzeżonym w Pythonie.
Więc zmieńmy to na
some_list = get_list()
if some_list:
Bardzo ważnym punktem, którego wiele rozwiązań tutaj brakuje, jest że wszystkie funkcje/metody Pythona domyślnie nie zwracają żadnej . Spróbuj wykonać poniższe czynności.
def does_nothing():
pass
foo = does_nothing()
print foo
O ile nie musisz zwracać None, aby zakończyć funkcję wcześniej, nie jest konieczne zwracanie jawnie None. Dość zwięźle, po prostu zwróć pierwszy wpis, gdyby istniał.
some_list = get_list()
if some_list:
return list[0]
I wreszcie, być może to było dorozumiane, ale żeby było jawne (ponieważ explicit jest lepszy niż implicit ), nie powinieneś mieć swojej funkcji get the list from another function; po prostu podaj go jako parametr. Tak więc końcowy wynik będzie
def get_first_item(some_list):
if some_list:
return list[0]
my_list = get_list()
first_item = get_first_item(my_list)
Jak mówiłem, operacja była prawie na miejscu, i tylko kilka akcentów nadaje mu smak pytona, którego szukasz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 22:54:01
Jeśli próbujesz wyrwać pierwszą rzecz (lub żadnej) z listy, możesz przełączyć się na generator, aby zrobić to tak:
next((x for x in blah if cond), None)
Pro: działa, jeśli blah nie jest indeksowalny Con: to nieznana składnia. Jest to przydatne podczas hakowania i filtrowania rzeczy w ipython.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-29 14:43:44
for item in get_list():
return item
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 21:48:57
Szczerze mówiąc, nie sądzę, że istnieje lepszy idiom: twój jest jasny i zwięzły - nie ma potrzeby niczego "lepszego". Może, ale to naprawdę kwestia gustu, można by zmienić if len(list) > 0:
na if list:
- pusta lista zawsze będzie oceniana na False.
W powiązaniu, Python jest a nie Perlem (no pun intended!), nie musisz zdobywać jak najfajniejszego kodu.
Właściwie, najgorszy kod jaki widziałem w Pythonie, był również bardzo fajny : -) i całkowicie nie do utrzymania.
By sposób, w jaki większość rozwiązań, które tu widziałem, nie bierze pod uwagę, gdy list[0] zwraca wartość False (np. pusty łańcuch lub zero) - w tym przypadku wszystkie zwracają None I not the correct element.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 23:14:19
Do diabła z tym, oto jeszcze jedna możliwość.
return None if not get_list() else get_list()[0]
Benefit: Ta metoda obsługuje przypadek, w którym get_list jest None, bez użycia try / except lub assignment. Z tego co wiem, żadna z powyższych implementacji nie poradzi sobie z tą możliwością
Upadki: funkcja get_list() jest wywoływana dwukrotnie, dość niepotrzebnie, szczególnie jeśli lista jest długa i / lub utworzona podczas wywoływania funkcji.
Prawda jest taka, że moim zdaniem bardziej" Pythoniczne " jest dostarczanie kodu, który jest czytelny niż zrobić jednolinijkowy tylko dlatego, że można:) muszę przyznać, że jestem winny wiele razy niepotrzebnie kompresji kodu Pythona tylko dlatego, że jestem pod wrażeniem, jak mały mogę sprawić, że złożona funkcja wygląda:)
Edytuj: Jak skomentował poniżej użytkownik "hasen j", powyższe wyrażenie warunkowe jest nowe w Pythonie 2.5, jak opisano tutaj: https://docs.python.org/whatsnew/2.5.html#pep-308 dzięki, hasen!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 03:23:52
Idiom Pythona zwracający pierwszą pozycję czy brak?
Najbardziej Pythoniczne podejście jest tym, co najbardziej upvoted odpowiedź zademonstrowała, i to była pierwsza rzecz, która przyszła mi do głowy, gdy czytałem pytanie. Oto jak go użyć, po pierwsze, jeśli ewentualnie pusta lista zostanie przekazana do funkcji: {]}
def get_first(l):
return l[0] if l else None
I jeśli lista jest zwracana z get_list
funkcji:
l = get_list()
return l[0] if l else None
Inne sposoby, aby to zrobić tutaj, z objaśnienia
for
Kiedy zacząłem myśleć o sprytnych sposobach, to jest druga rzecz, o której pomyślałem:]}
for item in get_list():
return item
Zakłada, że funkcja kończy się tutaj, domyślnie zwracając None
Jeśli get_list
zwraca pustą listę. Poniższy jawny kod jest dokładnie równoważny:
for item in get_list():
return item
return None
if some_list
Zaproponowano również następujące rozwiązanie (poprawiłem nieprawidłową nazwę zmiennej), które również używa implicit None
. Byłoby to lepsze od powyższego, ponieważ używa logicznego sprawdzenia zamiast iteracji, która może się nie wydarzyć. Powinno to być łatwiejsze do natychmiastowego zrozumienia, co się dzieje. Ale jeśli piszemy dla czytelności i konserwacji, powinniśmy również dodać wyraziste return None
na końcu:
some_list = get_list()
if some_list:
return some_list[0]
Slice or [None]
and select zeroth index
[[38]}ten jest również w najbardziej głosowanej odpowiedzi:
return (get_list()[:1] or [None])[0]
Plasterek jest niepotrzebny i tworzy dodatkową listę jednego elementu w pamięci. Poniżej powinno być więcej performant. Aby wyjaśnić, or
zwraca drugi element, jeśli pierwszy jest False
w kontekście logicznym, więc jeśli get_list
zwróci pustą listę, wyrażenie zawarte w nawiasach zwróci listę z "None", do której będzie dostęp za pomocą indeksu 0
:
return (get_list() or [None])[0]
Następny używa faktu, że i zwraca drugi element, jeśli pierwszy jest True
W kontekście logicznym, a ponieważ odwołuje się do my_list dwa razy, nie jest lepszy od wyrażenia trójkowego (i technicznie nie jest to one-liner):
my_list = get_list()
return (my_list and my_list[0]) or None
next
Następnie mamy następujące sprytne wykorzystanie wbudowanego next
i iter
return next(iter(get_list()), None)
Aby wyjaśnić, iter
zwraca iterator z metodą .next
. (.__next__
w Pythonie 3.) Następnie wbudowana metoda next
wywołuje tę metodę .next
, a jeśli iterator jest wyczerpany, Zwraca wartość domyślną, którą podajemy, None
.
Nadmiarowe wyrażenie ternary (a if b else c
) i krążące wstecz
Poniżej zaproponowano, ale odwrotność byłaby korzystniejsza, ponieważ logika jest zwykle lepiej rozumiane w pozytywie zamiast negatywu. Ponieważ get_list
jest wywoływane dwa razy, o ile wynik nie zostanie zapamiętany w jakiś sposób, będzie to działać słabo:
return None if not get_list() else get_list()[0]
Lepsza odwrotność:
return get_list()[0] if get_list() else None
Jeszcze lepiej, Użyj zmiennej lokalnej tak, że {[12] } jest wywoływana tylko jeden raz, i masz zalecane rozwiązanie Pythonic najpierw omówione:
l = get_list()
return l[0] if l else None
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 15:37:39
Z ciekawości, sprawdziłem czas na dwóch rozwiązaniach. Rozwiązanie, które używa instrukcji 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ą iterable.
import random
import timeit
def index_first_item(some_list):
if some_list:
return some_list[0]
def return_first_item(some_list):
for item in some_list:
return item
empty_lists = []
for i in range(10000):
empty_lists.append([])
assert empty_lists[0] is not empty_lists[1]
full_lists = []
for i in range(10000):
full_lists.append(list([random.random() for i in range(10)]))
mixed_lists = empty_lists[:50000] + full_lists[:50000]
random.shuffle(mixed_lists)
if __name__ == '__main__':
ENV = 'import firstitem'
test_data = ('empty_lists', 'full_lists', 'mixed_lists')
funcs = ('index_first_item', 'return_first_item')
for data in test_data:
print "%s:" % data
for func in funcs:
t = timeit.Timer('firstitem.%s(firstitem.%s)' % (
func, data), ENV)
times = t.repeat()
avg_time = sum(times) / len(times)
print " %s:" % func
for time in times:
print " %f seconds" % time
print " %f seconds avg." % avg_time
To są czasy, które mam:
empty_lists: index_first_item: 0.748353 seconds 0.741086 seconds 0.741191 seconds 0.743543 seconds avg. return_first_item: 0.785511 seconds 0.822178 seconds 0.782846 seconds 0.796845 seconds avg. full_lists: index_first_item: 0.762618 seconds 0.788040 seconds 0.786849 seconds 0.779169 seconds avg. return_first_item: 0.802735 seconds 0.878706 seconds 0.808781 seconds 0.830074 seconds avg. mixed_lists: index_first_item: 0.791129 seconds 0.743526 seconds 0.744441 seconds 0.759699 seconds avg. return_first_item: 0.784801 seconds 0.785146 seconds 0.840193 seconds 0.803380 seconds avg.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-16 07:07:33
Jeśli chodzi o idiomy, istnieje itertools recipe o nazwie nth
.
Z receptur itertools:
def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)
Jeśli chcesz jednolinijkowe, rozważ zainstalowanie biblioteki, która implementuje ten przepis dla Ciebie, np. more_itertools
:
import more_itertools as mit
mit.nth([3, 2, 1], 0)
# 3
mit.nth([], 0) # default is `None`
# None
Dostępne jest inne narzędzie, które zwraca tylko pierwszy element o nazwie more_itertools.first
.
mit.first([3, 2, 1])
# 3
mit.first([], default=None)
# None
Te narzędzia itertools skalują się ogólnie dla dowolnych iterowalnych, nie tylko dla list.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 17:15:13
def head(iterable):
try:
return iter(iterable).next()
except StopIteration:
return None
print head(xrange(42, 1000) # 42
print head([]) # None
BTW: przerobiłbym ogólny przepływ programu na coś takiego:
lists = [
["first", "list"],
["second", "list"],
["third", "list"]
]
def do_something(element):
if not element:
return
else:
# do something
pass
for li in lists:
do_something(head(li))
(unikanie powtarzania w miarę możliwości)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-16 13:23:21
A może tak:
(my_list and my_list[0]) or None
Notatka: powinno to działać poprawnie dla list obiektów, ale może zwrócić niepoprawną odpowiedź w przypadku listy liczb lub łańcuchów w komentarzach poniżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 15:17:42
Możesz użyć metody ekstrakcji . Innymi słowy wyodrębnij ten kod do metody, którą następnie wywołasz.
Nie próbowałbym go bardziej kompresować, Jedynka wydaje się trudniejsza do odczytania niż wersja słowna. A jeśli używasz metody Extract, to jest to jeden liner;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 20:10:04
try:
return a[0]
except IndexError:
return None
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 20:38:00
Użycie sztuczki and-or:
a = get_list()
return a and a[0] or None
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-12 23:53:16
A co z: next(iter(get_list()), None)
?
Może nie jest tu najszybszy, ale jest standardowy (począwszy od Pythona 2.6) i zwięzły.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 17:21:42
Prawdopodobnie nie najszybsze rozwiązanie, ale nikt nie wspomniał o tej opcji:
dict(enumerate(get_list())).get(0)
Jeśli get_list()
może zwrócić None
możesz użyć:
dict(enumerate(get_list() or [])).get(0)
Zalety:
- jedna linia
- wystarczy zadzwonić get_list()
raz
-łatwe do zrozumienia
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-04 18:37:07
Mój przypadek użycia polegał tylko na ustawieniu wartości zmiennej lokalnej.
Osobiscie znalazlem try i except style cleaner do przeczytania
items = [10, 20]
try: first_item = items[0]
except IndexError: first_item = None
print first_item
Niż krojenie listy.
items = [10, 20]
first_item = (items[:1] or [None, ])[0]
print first_item
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-20 07:00:51
if mylist != []:
print(mylist[0])
else:
print(None)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-25 10:13:22
Kilka osób zasugerowało zrobienie czegoś takiego:
list = get_list()
return list and list[0] or None
To działa w wielu przypadkach, ale będzie działać tylko wtedy, gdy list[0] nie jest równe 0, False lub pusty łańcuch. Jeśli list[0] ma wartość 0, False lub pusty łańcuch, metoda niepoprawnie zwróci None.
Stworzyłem ten błąd we własnym kodzie o jeden raz za dużo !
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-08 12:49:26
Czy idiomatyczny python nie jest odpowiednikiem trójnawowych operatorów w stylu C?]}
cond and true_expr or false_expr
Ie.
list = get_list()
return list and list[0] or None
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-15 16:20:43