Питання Як перевірити, чи список порожній?


Наприклад, якщо прийнято наступне:

a = []

Як перевірити, чи a пусто?


2728
2017-09-10 06:20


походження




Відповіді:


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

Використання неявної булевості порожнього списку досить пітонічно.


3907
2017-09-10 06:28



Граючи адвоката диявола. Я не розумію, чому ця ідіома вважається пітонічною. "Явний, краще, ніж неявний", правильно? Ця перевірка, здається, не дуже ясна про те, що таке перевірка. - James McMahon
@ JamesMcMahon - це компроміс між зрозумілістю та гнучкістю типів. як правило, "явний" означає не робити "магічні" речі. з іншого боку, "введення тиску" - це робота з більш загальними інтерфейсами, а не явна перевірка типів. так щось подібне if a == [] примушує певний тип (() == [] є False) Звідси загальний консенсус, здається, полягає в тому, що тираж качки виграє (насправді це говорить __nonzero__ це інтерфейс для тестування порожнечі docs.python.org/reference/datamodel.html#object.__nonzero__) - andrew cooke
Це закріплено в розділі "Рекомендації щодо програмування" PEP 8: "Для послідовностей (рядків, списків, кортежів) використовуйте той факт, що порожні послідовності є помилковими". - abarnert
ValueError: Значення істинності масиву з кількома елементами неоднозначне. Використовуйте a.any () або a.all () Я бачу цю помилку щоразу, коли масив має щось у ньому - PirateApp
@ PireattApp, ви повинні використовувати Numpy. Вони говорять про регулярні масиви. Для numpy, можливо, ви хочете використовувати 'is not None'? - Sam Bobel


Пітонічний спосіб зробити це є з PEP 8 стиль керівництва (де Так означає "рекомендовано" і Немає означає "не рекомендується"):

Для послідовностей (рядків, списків, кортежів) використовуйте той факт, що порожні послідовності є помилковими.   

Так: if not seq:
     if seq:

Немає:  if len(seq):
     if not len(seq):

865
2017-09-10 10:33



Другий спосіб здається кращим, якщо ви хочете це сигналізувати seq Очікується, що це буде якийсь об'єкт, подібний до списку. - BallpointBen
@ BallpointBen, який, на думку адвокатів піонізму, повинен бити на увазі, як максимально називається змінна - Aalok


Я віддаю перевагу цьому:

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

Це 100% зрозуміло, що li це послідовність (список), і ми хочемо перевірити його розмір. Моя проблема з if not li: ... це те, що він дає помилкове враження, що li є логічною змінною.


519
2017-09-05 00:30



Перевірка того, чи довжина списку дорівнює нулю, а не просто перевірка того, чи є цей список помилковим, є потворним та нептихонічним. Кожен, хто знайомий з Python, не буде думати li це болить взагалі, і не хвилюйтеся. Якщо це важливо, ви повинні додати коментар, а не більше коду. - Carl Smith
Це виглядає як необгрунтоване точне випробування, яке часто повільніше і завжди менш читабельно IMHO. Замість того, щоб перевірити розмір щось порожнє, чому б не просто перевірити, чи він порожній? - John B
У будь-якому випадку, причиною цього є погано (і що порушення ідіоми на мові з сильними ідіомами, такими як Python взагалі погано), це означає, що він повідомляє читачеві, що ви спеціально перевіряєте довжину чомусь (наприклад, тому що ви хочете None або 0підняти виняток, а не проходити). Отже, коли ви робите це без причини, це вводить в оману, і це також означає, що коли ваш код робить потрібно зробити різницю, ця відмінність невидима, тому що ви "плакали вовка" по всьому решті джерела. - abarnert
Я думаю, що це просто без потреби подовження коду. В іншому випадку, чому б не бути ще "явним" з if bool(len(li) == 0) is True:? - augurar
@ Ябба це буде O (1) у багатьох випадках (ті, де ви працюєте з вбудованими типами даних), але ви просто не можете покладатися на це. Ви можете працювати зі спеціальним типом даних, який не має цього ресурсу. Ви також можете вирішити додати цей спеціальний тип даних пізніше після того, як ви вже написали цей код. - ralokt


Інші люди, схоже, узагальнюють питання за винятком списків, тому я подумав, що додаду застереження для іншого типу послідовності, що може використовуватися багатьма людьми, особливо тому, що це перший гугл Google для "python test empty array" .

Інші методи не працюють для масивів numpy

Вам потрібно бути обережним з масивів numpy, оскільки інші методи, які працюють добре lists або інші стандартні контейнери виходять з ладу для масивів numpy. Я пояснюю, чому нижче, але, коротше кажучи, кращий спосіб це використовувати size.

"Пітонічний" спосіб не працює: Частина 1

"Pythonic" спосіб не вдається з використанням масивів numpy, оскільки numpy намагається відправити масив у масив boolс, і if x намагається оцінити всі ці boolвідразу ж для певної сукупності значення істинності. Але це не має сенсу, тому ви отримуєте a 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()

"Пітонічний" спосіб не працює: частина 2

Але, принаймні, випадок вище говорить вам, що це не вдалося. Якщо вам доведеться мати номерний масив із рівно одним елементом, то if Заява буде "працювати", у тому сенсі, що ви не отримаєте помилку. Однак, якщо такий один елемент буває 0 (або 0.0, або false, ...), if виправлення помилок false:

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

Але ясно x існує і не порожній! Цей результат не те, що ви хотіли.

Використовуючи len може дати несподівані результати

Наприклад,

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

повертає 1, хоча масив має нульові елементи.

Цифровий спосіб

Як пояснюється в scipy FAQ, правильний спосіб у всіх випадках, коли ви знаєте, що маєте масив numberpy, слід використовувати 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

Якщо ви не впевнені, це може бути list, чисельний масив чи щось інше, ви можете поєднати цей підхід з відповідь @dubiousjim дає щоб переконатися, що правильний тест використовується для кожного типу. Не дуже "пітонічний", але виявляється, що "чини" навмисно порушили пітонічність, принаймні в цьому сенсі.

Якщо вам потрібно зробити більше, ніж просто перевірити, чи вхід порожній, і ви використовуєте інші функції numpy, такі як індексування чи математичні операції, це, ймовірно, більш ефективне (і, звичайно, більш поширене) примушування введення бути номерний масив. Для цього дуже багато хороших функцій - найголовніше numpy.asarray. Це приймає ваш вхід, нічого не робить, якщо він вже масив, або обгорнув ваш вхід у масив, якщо це список, кортеж і т. Д., І, можливо, перетворить його на обраний вами dtype. Так що це дуже швидко, коли це може бути, і це гарантує, що ви просто переконаєтеся, що вхідний файл - масив numberpy. Зазвичай, ми просто використовуємо одне ім'я, оскільки перетворення в масив не повернеться назад за межі поточного обсяг:

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

Це зробить x.size перевірте роботу у всіх випадках, які я бачу на цій сторінці.


209
2018-02-21 16:48



Варто зазначити, що це не є недоліком в Python, а швидше навмисним розривом контракту numpy - numpy це бібліотека з дуже конкретним випадком використання, і вона має інше "природне" визначення того, що правдивість масиву до стандарту Python для контейнерів. Це має сенс оптимізувати для цього випадку, у такий спосіб pathlib використовує / щоб об'єднати шляхи замість + - це нестандартно, але має сенс у контексті. - Gareth Latty
Згоден Моя точка полягає в тому, що важливо пам'ятати, що numpy зробив вибір, щоб перервати введення качки як для дуже поширених if x і len(x) ідіоми - і іноді цей полом може бути дуже важко виявляти та налагоджувати. - Mike
Я не знаю, для мене, якщо метод, який називається len (x), не повертає довжину масиву, оскільки припущення, його ім'я погано розроблено. - Dalton
Це питання не має нічого спільного з масивами numpy - ppperry
@ppperry Так, оригінальне питання не про Numpy масиви, але при роботі з тими, і, можливо, качці введені аргументи, це питання стає дуже актуальним. - peterhil


Пустий список вважається помилковим при перевірці справжнього значення (див документація на python):

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

@ Дарен Томас

EDIT: ще один момент проти тестування   порожній список як False: як щодо   поліморфізм? Ви не повинні залежати від цього   перелік список. Це має бути просто   Чорт, як качка - як ти їдеш?   щоб здобути свою качку   '' False '', коли він не містить елементів?

Ваша качкаКолекція повинна виконуватись __nonzero__ або __len__ тому якщо a: буде працювати без проблем.


104
2017-09-10 06:31





Найкращий спосіб перевірити, чи список порожній

Наприклад, якщо прийнято наступне:

a = []

Як перевірити, чи а порожня?

Коротка відповідь:

Помістіть список у логічний контекст (наприклад, з if або while заява) Це буде тестувати False якщо він порожній, і True інакше Наприклад:

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

Звернення до повноважень

PEP 8, офіційний путівник Python для коду Python у стандартній бібліотеці Python, стверджує:

Для послідовностей (рядків, списків, кортежів) використовуйте той факт, що порожні послідовності є помилковими.

Yes: if not seq:
     if seq:

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

Ми повинні очікувати, що стандартний код бібліотеки повинен бути максимально продуктивним та правильним. Але чому це справа, і чому нам потрібні ці вказівки?

Пояснення

Я часто бачу код, подібний до цього, від досвідчених програмістів до Python:

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

І користувачі ледачих мов можуть спокусити це:

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

Вони правильні у відповідних інших мовах. І це навіть семантично правильно в Python.

Але ми вважаємо це не-пітонічним, оскільки Python підтримує ці семантики безпосередньо в інтерфейсі об'єкта списку за допомогою логічного примусу.

Від документи (і особливо відзначити включення порожнього списку, []):

За замовчуванням об'єкт вважається істинним, якщо не визначено його клас   або а __bool__() метод, який повертає False або a __len__() метод   що повертає нуль, коли викликається з об'єктом. Ось більшість вбудованих об'єктів вважаються помилковими:

  • константи визначаються як хибні: None і False.
  • нуль будь-якого числового типу: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • порожні послідовності та колекції: '', (), [], {}, set(), range(0)

І датамодель документації:

object.__bool__(self)

Закликаний до здійснення тестування значення істини та вбудованої операції bool(); повинен повернутися False або True. Коли цей метод не визначено,    __len__() викликається, якщо він визначений, і об'єкт вважається істинним, якщо його результат ненульовий. Якщо клас не визначає ні __len__()   ні __bool__(), всі його приклади вважаються вірними.

і

object.__len__(self)

Закликаний до реалізації вбудованої функції len(). Має повернути довжину об'єкта, ціле число> = 0. Також об'єкт, який не визначає a __bool__() метод і чого __len__() метод returns zero вважається ложним у логічному контексті.

Тому замість цього:

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

або це:

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

Зробити це:

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

Використовуючи те, що Pythonic звичайно сплачує у виконанні:

Чи окупиться? (Зверніть увагу, що краще провести час для виконання еквівалентної операції :)

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

Для масштабу, ось вартість виклику функції та побудови та повернення порожнього списку, яку ви можете відняти від витрат на перевірки порожньої суми, що використовуються вище:

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

Ми бачимо це або перевірка довжини з вбудованою функцією len у порівнянні з 0  або перевірка на порожній список є багато чого менш продуктивний, ніж використання вбудованого синтаксису мови як задокументованого.

Чому?

Для len(a) == 0 перевірити:

Перший Python повинен перевірити globals, щоб побачити, якщо len тіні

Потім він повинен викликати функцію, завантажити 0, і порівняння рівності в Python (а не з 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

І для [] == [] він повинен створити непотрібний список, а потім знову виконати операцію порівняння на віртуальній машині Python (на відміну від C)

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

Шлях "Pythonic" є набагато простішою і швидшою перевіркою, оскільки довжина списку кешується в заголовку об'єкта об'єкта:

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

Докази з джерела та документації

PyVarObject

Це розширення PyObject що додає ob_size поле Це використовується лише для об'єктів, які мають певне поняття про довжину. Цей тип не часто з'являється в API Python / C. Це відповідає полям, визначеним розширенням PyObject_VAR_HEAD макрос

З джерела c в Включити / 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

Мені подобалося досліджувати це, і я витрачаю багато часу на мої відповіді. Якщо ви думаєте, що я залишаю щось, повідомте мені про це в коментарях.


83
2017-08-20 03:50



Це IMO дуже добре читається і цінний внесок (відповідаючи на дев'ять років після того, як питання було поставлено, може бути якийсь запах, але не в цьому випадку принаймні для мене). Спасибі Аарону. - Dilettant
@Dilettant Запахи - правила великого пальця або евристики, які змушують нас виглядати ближче. Деякі нові користувачі публікують пізніше відповіді, які, по суті, копіюють інші відповіді, і це те, що ми турбуємося, коли справа доходить до пізніх відповідей. Пізніх відповідей на додану вартість є Тим не менш, бажано, однак - інакше ми закрили б повідомлення після деякого періоду часу, як це робить Reddit. - Aaron Hall♦


Патрик (прийнятий) відповідь правильно: if not a: це правильний спосіб зробити це. Відповідь Харлі Голкомба правильно, що це в керівництві по стилю PEP 8. Але чому жоден із відповідей не пояснює, чому гарна ідея слідувати за ідіомістю, навіть якщо ви особисто вважаєте, що це недостатньо явний або незрозумілий для користувачів Ruby або що завгодно.

Код Python і спільнота Python мають дуже сильні ідіоми. Слідуючи цим ідіоми, ваш код простіше читається для тих, хто має досвід роботи в Python. І коли ви порушуєте ці ідіоми, це сильний сигнал.

Це правда, що if not a: не відрізняє порожні списки від None, числові 0, порожні кортежі або порожні користувацькі типи збірки, або порожні створені не зовсім типи збірки, або одномандатний масив NumPy, що діє як скаляри з помилковими значеннями і т. д. Іноді важливо бути ясно про це. І в такому випадку ти знаєш що Ви хочете бути чітко визначеними, щоб ви могли точно протестувати. Наприклад, if not a and a is not None:означає "щось хибне, крім ніхто", в той час як if len(a) != 0: означає "лише порожні послідовності - і все, крім послідовності, тут помилка" і так далі. Крім тестування точно те, що ви хочете протестувати, це також сигналізує читачеві, що цей тест важливий.

Але коли у вас немає чогось чітко про щось, крім іншого if not a: вводить в оману читача. Ви сигналізуєте щось важливе, коли це не так. (Ви також можете зробити код менш гнучким, або повільним або щось інше, але це все менш важливо.) А якщо ви звичайно вводити в оману читача так, то, коли ти робити потрібно зробити різницю, це буде проходити непомітно, тому що ви "плач вола" по всьому коду.


82
2017-12-03 02:21





Я бачив нижче, як бажаний:

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

63
2017-09-10 06:28



None не список; це його власний тип. - Yann Vernier