Vraag Hoe kan ik controleren of een lijst leeg is?


Bijvoorbeeld als het volgende is doorgegeven:

a = []

Hoe kan ik controleren om te zien of a is leeg?


2718
2017-09-10 06:20


oorsprong


antwoorden:


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

Het gebruik van de impliciete booleanness van de lege lijst is vrij pythonisch.


3886
2017-09-10 06:28



De pythonische manier om het te doen is van de PEP 8-stijlgids (waar Ja betekent "aanbevolen" en Nee betekent "niet aanbevolen"):

Voor reeksen, (strings, lijsten, tuples), gebruik het feit dat lege reeksen onwaar zijn.   

Ja: if not seq:
     if seq:

Nee:  if len(seq):
     if not len(seq):

862
2017-09-10 10:33



Ik geef er de voorkeur aan expliciet:

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

Op deze manier is het 100% duidelijk dat li is een reeks (lijst) en we willen de grootte ervan testen. Mijn probleem met if not li: ... is dat het de verkeerde indruk geeft dat li is een Booleaanse variabele.


517
2017-09-05 00:30



Andere mensen lijken de vraag verder te generaliseren dan alleen lijsten, dus ik dacht dat ik een waarschuwing zou toevoegen voor een ander type reeks dat veel mensen zouden kunnen gebruiken, vooral omdat dit de eerste google-hit is voor "Python-test lege array" .

Andere methoden werken niet voor numpy arrays

Je moet voorzichtig zijn met numpy arrays, omdat andere methoden goed werken lists of andere standaardcontainers falen voor numpy arrays. Ik leg uit waarom hieronder, maar in het kort, de voorkeursmethode is om te gebruiken size.

De "pythonische" manier werkt niet: deel 1

De "pythonic" -manier faalt met numpy arrays omdat numpy de array naar een array van probeert te casten bools, en if x probeert al deze te evalueren bools meteen voor een soort geaggregeerde waarheidswaarde. Maar dit slaat nergens op, dus u krijgt een 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()

De "pythonische" manier werkt niet: deel 2

Maar in ieder geval vertelt het bovenstaande geval dat het faalde. Als je toevallig een numpy array hebt met precies één element, dan is de if verklaring zal "werken", in die zin dat u geen fout krijgt. Echter, als dat ene element toevallig is 0 (of 0.0of false, ...), de if verklaring zal onjuist resulteren in false:

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

Maar duidelijk x bestaat en is niet leeg! Dit resultaat is niet wat je wilde.

Gebruik makend van len kan onverwachte resultaten geven

Bijvoorbeeld,

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

geeft 1 terug, ook al heeft de array nul elementen.

De numpythonische manier

Zoals uitgelegd in de scipy FAQ, de juiste methode in alle gevallen waarin je weet dat je een numpy array hebt om te gebruiken 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

Als u niet zeker weet of het misschien een is list, een numpy array of iets anders, je zou deze aanpak kunnen combineren met het antwoord dat @ dubiousjim geeft om ervoor te zorgen dat de juiste test voor elk type wordt gebruikt. Niet erg "pythonisch", maar het blijkt dat numpy opzettelijk pythoniciteit heeft verbroken in tenminste deze zin.

Als u meer wilt doen dan alleen controleren of de invoer leeg is en u andere numpy-functies zoals indexering of wiskundige bewerkingen gebruikt, is het waarschijnlijk efficiënter (en zeker vaker) om de invoer te forceren zijn een numpy array. Er zijn een paar leuke functies om dit snel te doen - belangrijker nog numpy.asarray. Dit neemt je input, doet niets als het al een array is, of verpakt je invoer in een array als het een lijst, tuple, enz. Is, en converteert het optioneel naar je gekozen dtype. Dus het is erg snel wanneer het ook maar kan zijn, en het zorgt ervoor dat je er gewoon vanuit gaat dat de invoer een numpy array is. We gebruiken meestal zelfs dezelfde naam, omdat de conversie naar een array het niet buiten de stroom haalt strekking:

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

Dit zal het maken x.size controleer het werk in alle gevallen die ik op deze pagina zie.


208
2018-02-21 16:48



Een lege lijst wordt zelf als fout beschouwd bij het testen van de werkelijke waarde (zie python documentatie):

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

@Daren Thomas

EDIT: Nog een punt tegen testen   de lege lijst als False: What about   polymorfisme? Je moet niet afhankelijk zijn van   een lijst is een lijst. Het zou gewoon moeten   kwaken als een eend - hoe gaat het met je   om je duckCollection te kwaken   '' Niet waar "als er geen elementen zijn?

Je duckCollection moet implementeren __nonzero__ of __len__ dus de als a: werkt zonder problemen.


103
2017-09-10 06:31



Patrick's (geaccepteerde) antwoord heeft gelijk: if not a: is de juiste manier om het te doen. Harley Holcombe's antwoord heeft gelijk dat dit in de PEP 8-stijlgids staat. Maar wat geen van de antwoorden verklaart, is waarom het een goed idee is om het idioom te volgen, zelfs als je persoonlijk vindt dat het niet expliciet genoeg of verwarrend is voor Ruby-gebruikers of wat dan ook.

Python-code en de Python-community hebben een zeer sterk idioom. Het volgen van deze idioom maakt uw code leesbaarder voor iedereen die ervaring heeft met Python. En als je die idioom overtreedt, is dat een sterk signaal.

Het is waar dat if not a: maakt geen onderscheid tussen lege lijsten en None, of numerieke 0, of lege tuples, of lege door de gebruiker gemaakte verzamelingstypen, of lege door de gebruiker gemaakte niet-vrij-verzameltypen, of NumPy-array met één element die optreedt als scalaires met falsey-waarden, etc. En soms is het belangrijk om te zijn expliciet daarover. En in dat geval, weet je dat wat waar je expliciet over wilt zijn, dus je kunt precies dat testen. Bijvoorbeeld, if not a and a is not None: betekent "alles falsey behalve None", terwijl if len(a) != 0: betekent 'alleen lege reeksen' en alles behalve een reeks is hier een fout, enzovoort. Naast het testen van precies wat u wilt testen, geeft dit ook aan de lezer aan dat deze test belangrijk is.

Maar als je niets hebt om expliciet over te zijn, iets anders dan if not a: misleidt de lezer. Je signaleert iets als belangrijk als het dat niet is. (U kunt de code ook minder flexibel maken, of langzamer, of wat dan ook, maar dat is allemaal minder belangrijk.) En als u gewoon de lezer op deze manier misleiden, dan wanneer u do moet een onderscheid maken, het gaat onopgemerkt voorbijgaan omdat je overal in je code "huilt".


81
2017-12-03 02:21



Beste manier om te controleren of een lijst leeg is

Bijvoorbeeld als het volgende is doorgegeven:

a = []

Hoe controleer ik of a leeg is?

Kort antwoord:

Plaats de lijst in een Booleaanse context (bijvoorbeeld met een if of whileuitspraak). Het zal testen False als het leeg is, en True anders. Bijvoorbeeld:

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

Beroep op autoriteit

PEP 8, de officiële Python-stijlgids voor Python-code in de standaardbibliotheek van Python, beweert:

Voor reeksen, (strings, lijsten, tuples), gebruik het feit dat lege reeksen onwaar zijn.

Yes: if not seq:
     if seq:

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

We mogen verwachten dat de standaardbibliotheekcode zo performant en correct mogelijk moet zijn. Maar waarom is dat het geval, en waarom hebben we deze begeleiding nodig?

Uitleg

Ik zie vaak code zoals deze van ervaren programmeurs die nog niet bekend zijn met Python:

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

En gebruikers van luie talen kunnen in de verleiding komen om dit te doen:

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

Deze zijn correct in hun respectievelijke andere talen. En dit is zelfs semantisch correct in Python.

Maar we beschouwen het als niet-pythisch, omdat Python deze semantiek rechtstreeks ondersteunt in de interface van het lijstobject via booleaanse dwang.

Van de docs (en let specifiek op de opname van de lege lijst, []):

Standaard wordt een object als 'waar' beschouwd, tenzij de klasse dit definieert   ofwel een __bool__() methode die terugkeert False of a __len__() methode   die nul retourneert, wanneer deze met het object wordt aangeroepen. Hier zijn de meeste ingebouwde objecten die als fout worden beschouwd:

  • constanten gedefinieerd als false: None en False.
  • nul van elk type numeriek: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • lege reeksen en collecties: '', (), [], {}, set(), range(0)

En de datamodel documentatie:

object.__bool__(self)

Geroepen om het testen van de waarheidswaarde en de ingebouwde werking uit te voeren bool(); zou terug moeten keren False of True. Wanneer deze methode niet is gedefinieerd,    __len__() wordt genoemd, als het is gedefinieerd, en het object wordt als 'waar' beschouwd als het resultaat niet nul is. Als een klasse geen van beide definieert __len__()   noch __bool__(), al zijn gevallen worden als waar beschouwd.

en

object.__len__(self)

Bellen om de ingebouwde functie te implementeren len(). Moet de lengte van het object retourneren, een geheel getal> = 0. Ook een object dat geen a definieert __bool__() methode en van wie __len__() methode returns zero wordt als false beschouwd in een Booleaanse context.

Dus in plaats van dit:

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

of dit:

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

Doe dit:

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

Doen wat Pythonic is, levert meestal prestaties op:

Loont het? (Merk op dat minder tijd om een ​​gelijkwaardige bewerking uit te voeren beter is :)

>>> 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

Voor schaal zijn hier de kosten voor het aanroepen van de functie en het samenstellen en retourneren van een lege lijst, die u kunt aftrekken van de kosten van de leegheidscontroles die hierboven zijn gebruikt:

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

We zien dat een van beide controleren op lengte met de ingebouwde functie len in vergelijking tot 0  of controleren tegen een lege lijst is veel minder performant dan het gebruik van de ingebouwde syntaxis van de taal zoals gedocumenteerd.

Waarom?

Voor de len(a) == 0 controleren:

Eerst moet Python de globals controleren om te zien of len is overschaduwd.

Dan moet het de functie bellen, laden 0, en doe de gelijkheidsvergelijking in Python (in plaats van met 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

En voor de [] == []het moet een onnodige lijst maken en dan opnieuw de vergelijkingsbewerking uitvoeren in de virtuele machine van Python (in tegenstelling tot C)

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

De "Pythonic" -manier is een veel eenvoudigere en snellere controle, omdat de lengte van de lijst wordt gecached in de kop van de objectinstantie:

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

Bewijs uit de C-bron en documentatie

PyVarObject

Dit is een extensie van PyObject dat voegt het toe ob_size veld. Dit wordt alleen gebruikt voor objecten met een idee van lengte. Dit type verschijnt niet vaak in de Python / C API. Het komt overeen met de velden gedefinieerd door de uitbreiding van de PyObject_VAR_HEAD macro.

Van de c-bron in Inclusief / 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

Ik heb genoten van dit onderzoek en besteed veel tijd aan het ordenen van mijn antwoorden. Als u denkt dat ik iets weglaat, kunt u me dit laten weten in een opmerking.


80
2017-08-20 03:50



Ik heb de onderstaande gezien als de voorkeur:

if not a:
    print("The list is empty or null")

62
2017-09-10 06:28



Waarom helemaal inchecken

Niemand lijkt te hebben aangesproken je te ondervragen nodig hebben om de lijst in de eerste plaats te testen. Omdat u geen extra context heeft opgegeven, kan ik me voorstellen dat u deze controle wellicht niet in de eerste plaats hoeft uit te voeren, maar onbekend bent met het verwerken van lijsten in Python.

Ik zou zeggen dat het meest pythonic manier is om helemaal niet te controleren, maar om de lijst gewoon te verwerken. Op die manier zal het het juiste doen, of het nu leeg of vol is.

a = []

for item in a:
    <do something with item>

<rest of code>

Dit heeft het voordeel dat het de inhoud van een, terwijl er geen specifieke controle op leegte vereist is. Als een is leeg, het afhankelijke blok zal niet worden uitgevoerd en de interpreter zal doorgaan naar de volgende regel.

Als je de array daadwerkelijk op leegte moet controleren, zijn de andere antwoorden voldoende.


50
2017-10-06 19:25



len() is een O (1) -bewerking voor Python-lijsten, tekenreeksen, dictaten en sets. Python houdt intern het aantal elementen in deze containers bij.

JavaScript heeft een soortgelijk idee van waarachtig / vals.


44
2017-09-15 05:50



Ik had geschreven:

if isinstance(a, (list, some, other, types, i, accept)) and not a:
    do_stuff

die werd verkozen tot -1. Ik weet niet zeker of dat komt omdat lezers bezwaar maakten tegen de strategie of dachten dat het antwoord niet nuttig was zoals gepresenteerd. Ik zal doen alsof het de laatste was, want --- wat telt als "pythonisch" --- dit is de juiste strategie. Tenzij je al hebt uitgesloten, of bereid bent om zaken af ​​te handelen waar a is bijvoorbeeld False, je hebt een test nodig die restrictiever is dan alleen if not a:. Je zou zoiets als dit kunnen gebruiken:

if isinstance(a, numpy.ndarray) and not a.size:
    do_stuff
elif isinstance(a, collections.Sized) and not a:
    do_stuff

de eerste test is in reactie op het antwoord van @ Mike hierboven. De derde regel kan ook worden vervangen door:

elif isinstance(a, (list, tuple)) and not a:

als u alleen exemplaren van bepaalde typen (en hun subtypen) wilt accepteren, of met:

elif isinstance(a, (list, tuple)) and not len(a):

Je kunt wegkomen zonder de expliciete typecontrole, maar alleen als de omringende context je dat al verzekert a is een waarde van de typen die u wilt verwerken, of als u zeker weet dat typen die u niet kunt verwerken fouten veroorzaken (bijv. TypeError als je belt len op een waarde waarvoor het ongedefinieerd is) die u bereid bent aan te pakken. Over het algemeen lijken de "pythonische" conventies deze laatste weg te gaan. Knijp het als een eend en laat een DuckError opstaan ​​als hij niet weet hoe hij moet kwaken. Dat moet je nog steeds doen denken Over wat voor soort aannames je aan het doen bent, en of de zaken die je niet goed kunt afhandelen echt fout gaan op de juiste plaatsen. De Numpy-arrays zijn een goed voorbeeld waar je gewoon blind op kunt vertrouwen len of de booleaanse typecast doet mogelijk niet precies wat u verwacht.


28
2018-05-31 14:35