Pytanie Jak sprawdzić, czy lista jest pusta?


Na przykład, jeśli przekazano:

a = []

Jak sprawdzić, czy a jest pusty?


2729
2017-09-10 06:20


pochodzenie




Odpowiedzi:


if not a:
  print("List is empty")

Używanie niejawnej wartości boolowskiej pustej listy jest dość pythonic.


3907
2017-09-10 06:28



Grając adwokata diabła. Nie rozumiem, dlaczego ten idiom jest uważany za python. "Jawność jest lepsza niż domniemana", prawda? Ta kontrola nie wydaje się bardzo jednoznaczna na temat tego, co jest sprawdzane. - James McMahon
@JamesMcMahon - to kompromis pomiędzy elastycznością i elastycznością. ogólnie mówiąc "bycie otwartym" oznacza nie robienie "magicznych" rzeczy. z drugiej strony "pisanie z kaczką" oznacza raczej pracę z bardziej ogólnymi interfejsami niż jawne sprawdzanie typów. więc coś w stylu if a == [] wymusza określony typ (() == [] jest False). tutaj wydaje się, że powszechne porozumienie wydaje się, że pisanie na maszynie kacze wygrywa (w efekcie, mówiąc to __nonzero__ jest interfejsem do testowania pustki docs.python.org/reference/datamodel.html#object.__nonzero__) - andrew cooke
Jest to określone w sekcji "Zalecenia dotyczące programowania" w PEP 8: "W przypadku sekwencji, (łańcuchów, list, krotek), używaj tego, że puste sekwencje są fałszywe." - abarnert
ValueError: Wartość prawdy tablicy z więcej niż jednym elementem jest niejednoznaczna. Użyj a.any () lub a.all () Widzę ten błąd, gdy tablica ma coś w nim - PirateApp
@PireattApp, musisz używać Numpy. Mówią o regularnych tablicach. Dla numpy, może chcesz użyć 'is not None'? - Sam Bobel


Pythoniczny sposób na to jest z Przewodnik po stylu PEP 8 (gdzie tak oznacza "zalecane" i Nie oznacza "niezalecane"):

W przypadku sekwencji (łańcuchów, list, krotek) należy użyć faktu, że puste sekwencje są fałszywe.   

Tak: if not seq:
     if seq:

Nie:  if len(seq):
     if not len(seq):

865
2017-09-10 10:33



Drugi sposób wydaje się lepszy, jeśli chcesz to zasygnalizować seq ma być jakimś obiektem przypominającym listę. - BallpointBen
@BallpointBen, co powiedzieliby zwolennicy Pythonizmu, powinno być ukryte w nazwie zmiennej, tak bardzo jak to możliwe - Aalok


Wolę go jednoznacznie:

if len(li) == 0:
    print('the list is empty')

W ten sposób jest to w 100% jasne li jest sekwencją (listą) i chcemy przetestować jej rozmiar. Mój problem z if not li: ... jest to, że daje fałszywe wrażenie, że li jest zmienną binarną.


519
2017-09-05 00:30



Sprawdzanie, czy długość listy jest równa zero, a nie tylko sprawdzanie, czy lista jest fałszywa, czy jest brzydka i niepytonowa. Każdy, kto zna Pythona, nie pomyśli li jest w ogóle boolem i nie obchodzi go to. Jeśli jest to ważne, powinieneś dodać komentarz, a nie więcej kodu. - Carl Smith
Wydaje się, że jest to niepotrzebnie precyzyjny test, który jest często wolniejszy i zawsze jest mniej czytelny IMHO. Zamiast sprawdzać rozmiar czegoś pustego, dlaczego nie sprawdzić, czy jest pusty? - John B
W każdym razie powodem, dla którego jest to złe (i że łamanie idiomów w języku o silnych idiomach takich jak Python ogólnie jest złe) jest to, że sygnalizuje czytelnikowi, że specjalnie sprawdzasz długość z jakiegoś powodu (np. Ponieważ chcesz None lub 0 raczej podnieść wyjątek niż przejść). Tak więc, kiedy robisz to bez powodu, to wprowadza w błąd - i oznacza to również, kiedy twój kod robi trzeba dokonać rozróżnienia, rozróżnienie jest niewidoczne, ponieważ "wykrzyknąłeś wilk" w całym źródle. - abarnert
Myślę, że to po prostu niepotrzebnie wydłuża kod. W przeciwnym razie, dlaczego nie być jeszcze bardziej "jednoznaczny" z if bool(len(li) == 0) is True:? - augurar
@Jabba będzie O (1) w wielu przypadkach (te, w których pracujesz z wbudowanymi typami danych), ale po prostu nie możesz na tym polegać. Być może pracujesz z niestandardowym typem danych, który nie ma tej właściwości. Możesz również zdecydować o dodaniu tego niestandardowego typu danych później, po napisaniu tego kodu. - ralokt


Inne osoby wydają się uogólniać to pytanie poza same listy, więc pomyślałem, że dodam zastrzeżenie dla innego typu sekwencji, z którego może korzystać wielu ludzi, zwłaszcza, że ​​jest to pierwsze trafienie w Google dla "testu pustego tablicy Pythona" .

Inne metody nie działają dla numpy tablic

Musisz uważać na numpy array, ponieważ inne metody działają dobrze lists lub inne standardowe kontenery nie udają się dla numpy tablic. Wyjaśniam, dlaczego poniżej, ale w skrócie, preferowana metoda jest użycie size.

"Pythoniczny" sposób nie działa: Część 1

"Pythoniczny" sposób kończy się niepowodzeniem z numpy tablic, ponieważ numpy próbuje rzucić tablicę do tablicy bools, i if x próbuje ocenić wszystkie te bools naraz za jakąś zagregowaną wartość prawdy. Ale to nie ma sensu, więc dostajesz ValueError:

>>> x = numpy.array([0,1])
>>> if x: print("x")
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

"Pythoniczny" sposób nie działa: Część 2

Ale przynajmniej powyższy przypadek mówi, że się nie udało. Jeśli masz tablicę numpy z dokładnie jednym elementem, to if oświadczenie będzie "działać", w tym sensie, że nie otrzymasz błędu. Jednakże, jeśli ten jeden element się stanie 0 (lub 0.0, lub false, ...), if instrukcja będzie niepoprawnie wynikła false:

>>> x = numpy.array([0,])
>>> if x: print("x")
... else: print("No x")
No x

Ale wyraźnie x istnieje i nie jest pusty! Ten wynik nie jest tym, czego chciałeś.

Za pomocą len może dać nieoczekiwane wyniki

Na przykład,

len( numpy.zeros((1,0)) )

zwraca 1, mimo że tablica ma zero elementów.

Sposób numpythonic

Jak wyjaśniono w scipy FAQ, poprawna metoda we wszystkich przypadkach, w których wiesz, że masz tablicę numpy if x.size:

>>> x = numpy.array([0,1])
>>> if x.size: print("x")
x

>>> x = numpy.array([0,])
>>> if x.size: print("x")
... else: print("No x")
x

>>> x = numpy.zeros((1,0))
>>> if x.size: print("x")
... else: print("No x")
No x

Jeśli nie jesteś pewien, czy to może być list, tablicę numpy lub coś innego, możesz połączyć to podejście z odpowiedź @dubiousjim daje aby upewnić się, że odpowiedni test jest stosowany dla każdego typu. Nie bardzo "pytonowo", ale okazuje się, że numpy umyślnie zerwał pytoniczność przynajmniej w tym sensie.

Jeśli potrzebujesz czegoś więcej niż tylko sprawdzenie, czy dane wejściowe są puste, i używasz innych numnych funkcji, takich jak indeksowanie lub operacje matematyczne, prawdopodobnie jest to bardziej wydajne (i na pewno bardziej powszechne) wymuszenie wprowadzenia być tablica numpy. Jest kilka fajnych funkcji do robienia tego szybko - co najważniejsze numpy.asarray. Spowoduje to wprowadzenie danych wejściowych, nic nie robi, jeśli jest już tablicą, lub opakowuje dane wejściowe w tablicę, jeśli jest to lista, krotka itd. I opcjonalnie konwertuje je na wybrane. dtype. Jest więc bardzo szybki, kiedy tylko może być, i zapewnia, że ​​po prostu zaczynasz przyjmować, że wejście jest tablicą numpy. Zwykle używamy nawet tej samej nazwy, ponieważ konwersja do tablicy nie spowoduje jej powrotu poza bieżący zakres:

x = numpy.asarray(x, dtype=numpy.double)

To sprawi, że x.size sprawdź pracę we wszystkich przypadkach, które widzę na tej stronie.


209
2018-02-21 16:48



Warto zauważyć, że nie jest to wada Pythona, ale raczej celowa przerwa w umowie numpy - numpy jest biblioteką o bardzo specyficznym zastosowaniu i ma inną "naturalną" definicję tego, jaka jest prawidłowość tablicy względem standardu Python dla kontenerów. Optymalny dla tego przypadku jest sens, w taki sposób pathlib używa / łączenie ścieżek zamiast + - jest niestandardowy, ale ma sens w kontekście. - Gareth Latty
Zgoda. Chodzi mi tylko o to, że ważne jest, aby pamiętać, że numpy dokonał wyboru, aby zerwać pisanie z kaczkami dla bardzo powszechnych if x i len(x) idiomy - i czasami takie złamanie może być bardzo trudne do wykrycia i debugowania. - Mike
Nie wiem, dla mnie, jeśli metoda o nazwie len (x) nie zwraca długości tablicy, ponieważ założenia, jej nazwa jest źle zaprojektowana. - Dalton
To pytanie nie ma nic wspólnego z numpy array - ppperry
@ppperry Tak, pierwotne pytanie nie dotyczyło tablic Numpy, ale podczas pracy z tymi, a może nawet z wprowadzonych argumentów, to pytanie staje się bardzo istotne. - peterhil


Pusta lista jest sama uważana za fałszywą w testowaniu prawdziwej wartości (zob dokumentacja Pythona):

a = []
if a:
     print "not empty"

@Daren Thomas

EDYCJA: Kolejny punkt przeciwko testowaniu   pusta lista jako Fałsz: A co z   wielopostaciowość? Nie powinieneś polegać   lista jest listą. Powinno tak być   znachor jak kaczka - jak leci   aby przekonać duckCollection do znachora   "Fałsz", gdy nie ma żadnych elementów?

Twój duckCollection powinien zaimplementować __nonzero__ lub __len__ więc jeśli a: zadziała bez problemów.


104
2017-09-10 06:31





Najlepszym sposobem sprawdzenia, czy lista jest pusta

Na przykład, jeśli przekazano:

a = []

Jak sprawdzić, czy a jest puste?

Krótka odpowiedź:

Umieść listę w kontekście boolowskim (na przykład z if lub while komunikat). Będzie testować False jeśli jest pusty i True Inaczej. Na przykład:

if not a:                           # do this!
    print('a is an empty list')

Apel do władz

PEP 8, oficjalny przewodnik po Pythonie dla kodu Pythona w standardowej bibliotece Pythona, zapewnia:

W przypadku sekwencji (łańcuchów, list, krotek) należy użyć faktu, że puste sekwencje są fałszywe.

Yes: if not seq:
     if seq:

No: if len(seq):
    if not len(seq):

Należy oczekiwać, że standardowy kod biblioteki powinien być tak wydajny i poprawny, jak to tylko możliwe. Ale dlaczego tak jest i dlaczego potrzebujemy tych wskazówek?

Wyjaśnienie

Często widzę kod od doświadczonych programistów do Pythona:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

I użytkownicy leniwych języków mogą być kuszeni, aby to zrobić:

if a == []:                         # Don't do this!
    print('a is an empty list')

Są one poprawne w ich odpowiednich językach. W Pythonie jest to nawet semantycznie poprawne.

Ale uważamy to za un-Pythonic, ponieważ Python obsługuje te semantyki bezpośrednio w interfejsie obiektu listy przez wymuszenie boolowskie.

Od docs (i odnotuj konkretnie włączenie pustej listy, []):

Domyślnie obiekt jest uznawany za prawdziwy, chyba że zdefiniuje go jego klasa   lub __bool__() metoda, która zwraca False lub __len__() metoda   która zwraca zero, po wywołaniu z obiektem. Oto większość wbudowanych obiektów uznawanych za fałszywe:

  • stałe zdefiniowane jako fałszywe: None i False.
  • zero dowolnego typu liczbowego: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • puste sekwencje i kolekcje: '', (), [], {}, set(), range(0)

Oraz dokumentacja modelu danych:

object.__bool__(self)

Wywoływane w celu przeprowadzenia testowania wartości prawdy i wbudowanej operacji bool(); powinien powrócić False lub True. Kiedy ta metoda nie jest zdefiniowana,    __len__() jest wywoływane, jeśli jest zdefiniowane, a obiekt jest uznawany za prawdziwy, jeśli jego wynik jest niezerowy. Jeśli klasa nie definiuje żadnej __len__()   ani __bool__()wszystkie jego wystąpienia są uważane za prawdziwe.

i

object.__len__(self)

Wywoływany w celu zaimplementowania wbudowanej funkcji len(). Powinna zwrócić długość obiektu, liczbę całkowitą> = 0. Również obiekt, który nie definiuje a __bool__() metoda i której __len__() metoda zwraca zero jest uważana za fałszywą w kontekście logicznym.

Zamiast tego:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

albo to:

if a == []:                     # Don't do this!
    print('a is an empty list')

Zrób to:

if not a:
    print('a is an empty list')

Robienie tego, co Python zazwyczaj przynosi efekty:

Czy to się opłaca? (Zauważ, że mniej czasu na wykonanie równoważnej operacji jest lepsze :)

>>> import timeit
>>> min(timeit.repeat(lambda: len([]) == 0, repeat=100))
0.13775854044661884
>>> min(timeit.repeat(lambda: [] == [], repeat=100))
0.0984637276455409
>>> min(timeit.repeat(lambda: not [], repeat=100))
0.07878462291455435

Dla skali, tutaj jest koszt wywołania funkcji i konstruowania i zwracania pustej listy, którą możesz odjąć od kosztów kontroli pustki zastosowanych powyżej:

>>> min(timeit.repeat(lambda: [], repeat=100))
0.07074015751817342

Widzimy to zarówno sprawdzanie długości za pomocą wbudowanej funkcji len w porównaniu do 0  lub sprawdzanie na pustej liście jest dużo mniej wydajne niż przy użyciu wbudowanej składni języka, jak udokumentowano.

Czemu?

Dla len(a) == 0 czek:

Najpierw Python musi sprawdzić globale, aby zobaczyć, czy len jest zacieniony.

Następnie musi wywołać funkcję, załaduj 0i wykonaj porównanie równości w Pythonie (zamiast w C):

>>> import dis
>>> dis.dis(lambda: len([]) == 0)
  1           0 LOAD_GLOBAL              0 (len)
              2 BUILD_LIST               0
              4 CALL_FUNCTION            1
              6 LOAD_CONST               1 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

I dla [] == [] musi zbudować niepotrzebną listę, a następnie ponownie wykonać operację porównania w wirtualnej maszynie Pythona (w przeciwieństwie do C)

>>> dis.dis(lambda: [] == [])
  1           0 BUILD_LIST               0
              2 BUILD_LIST               0
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

Sposób "Pythoniczny" jest znacznie prostszy i szybszy, ponieważ długość listy jest buforowana w nagłówku instancji obiektu:

>>> dis.dis(lambda: not [])
  1           0 BUILD_LIST               0
              2 UNARY_NOT
              4 RETURN_VALUE

Dowody ze źródła C i dokumentacji

PyVarObject

To jest rozszerzenie PyObject to dodaje ob_size pole. Jest to używane tylko w przypadku obiektów, które mają pojęcie długości. Ten typ nie pojawia się często w interfejsie API Python / C. Odpowiada on polom zdefiniowanym przez rozszerzenie PyObject_VAR_HEAD makro.

Ze źródła c w Dołącz / listobject.h:

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size

Cieszyłem się badaniem tego i spędzam dużo czasu na udzielaniu odpowiedzi na moje pytania. Jeśli myślisz, że coś opuszczę, daj mi znać w komentarzu.


83
2017-08-20 03:50



To IMO jest całkiem dobrą lekturą, a cenny wkład (odpowiedź po dziewięciu latach od postawienia pytania może mieć jakiś zapach, ale nie w tym przypadku przynajmniej dla mnie). Dzięki Aaron. - Dilettant
@Dilettant Smells to zasady kciuka lub heurystyki, dzięki którym możemy się bliżej przyjrzeć. Niektórzy nowi użytkownicy publikują późno odpowiedzi, które zasadniczo kopiują inne odpowiedzi, i właśnie tego rodzaju obawy budzą późne odpowiedzi. Późne odpowiedzi, które dodają wartości są bardzo mile widziane - w przeciwnym razie zamykalibyśmy posty po pewnym czasie, tak jak robi to Reddit. - Aaron Hall♦


Patricka (przyjęta) odpowiedź jest w porządku: if not a: to właściwa droga. Odpowiedź Harleya Holcombe'a ma rację, że jest to w przewodniku po stylu PEP 8. Ale żadna z odpowiedzi nie wyjaśnia, dlaczego warto postępować zgodnie z idiomem - nawet jeśli osobiście uznasz, że nie jest to wystarczająco jasne lub mylące dla użytkowników Ruby lub cokolwiek innego.

Kod Pythona i społeczność Pythona mają bardzo mocne idiomy. Podążanie za tymi idiomami ułatwia czytanie Twojego kodu każdemu, kto ma doświadczenie w Pythonie. A kiedy łamiesz te idiomy, jest to silny sygnał.

To prawda, że if not a: nie odróżnia pustych list od Nonelub 0, pustych krotek lub pustych typów kolekcji utworzonych przez użytkownika lub pustych typów zbierania niezupełnie zbieranych przez użytkownika lub jednoczęściowa tablica NumPy działająca jak skalary z wartościami falsey itd. A czasami ważne jest, aby być jednoznacznie o tym. I w takim razie wiesz co chcesz być jednoznaczny, abyś mógł dokładnie to sprawdzić. Na przykład, if not a and a is not None:oznacza "wszystko falsey oprócz Brak", podczas gdy if len(a) != 0: oznacza "tylko puste sekwencje - a wszystko poza sekwencją jest tutaj błędem" i tak dalej. Poza testowaniem dokładnie tego, co chcesz przetestować, to również sygnalizuje czytelnikowi, że ten test jest ważny.

Ale jeśli nie masz nic do wyrażenia, wszystko inne niż if not a: wprowadza czytelnika w błąd. Sygnalizujesz coś tak ważnego, kiedy nie jest. (Możesz także sprawić, by kod był mniej elastyczny, wolniejszy lub jakikolwiek inny, ale to wszystko mniej ważne.) A jeśli ty zwykle wprowadzić w błąd czytelnika w ten sposób, a następnie, gdy Ty zrobić trzeba dokonać rozróżnienia, przejdzie niezauważone, ponieważ byłeś "płaczącym wilkiem" na całym twoim kodeksie.


82
2017-12-03 02:21