L oop над пустым итератором не вызывает исключение - PullRequest
1 голос
/ 04 февраля 2020

Я на Python 3.6.7.

Я только что заметил, что for l oop над пустым списком не l oop даже один раз. После некоторой мысли, это имело некоторый смысл для меня. Т.е. al oop над нулевым (пустым) объектом возвращает ноль итераций.

iterable = []
for element in iterable:
    pass
print(element)
>>> NameError: name 'element' is not defined

Это означает, что тест внутри l oop не будет выполнен, если len(iterable) == 0.

iterable = []
for element in iterable:
    assert isinstance(element, int)
#nothing happens

Тогда как я могу уловить эту ситуацию?

Есть ли компактный встроенный способ вызвать ошибку, когда мой l oop не запускается, потому что итерируемый пуст?

Для отлова этой конкретной ситуации необходимо вручную:

  • проверить, что iterator не пусто, до проверки l oop
  • , что элемент был определен после л oop. Ни один из методов не кажется мне элегантным

И я могу закончить этот тест в каждом for l oop.

assert len(iterable) > 0
#loop

или

#loop
assert "element" in dir() #?

Ответы [ 3 ]

2 голосов
/ 04 февраля 2020

Зачем вам нужно что-то делать, если l oop не запускается, потому что список пуст? Это совершенно нормальное поведение. Если вы по какой-то причине ожидаете иметь хотя бы один элемент (возможно, отсутствие элементов в массиве является мерой ошибки в вашей программе), тогда проверьте, если len(iterator) == 0, как вы предлагали ранее. Это совершенно правильный способ сделать это.

Кстати, исключения - это путь к go в тех случаях, когда вы проверяете значения переменных et c. Утверждения представляют собой более жестко запрограммированную информацию для критических сбоев и НЕ ДОЛЖНЫ использоваться для сообщения об обычных ошибках, поскольку они не могут быть обработаны.

1 голос
/ 04 февраля 2020

Нет встроенного способа напрямую проверять наличие пустых итераторов. Пустые итераторы обычно не считаются исключительными. Однако вы можете определить компактные помощники для явной проверки на наличие пустых итераторов.


Обнаружение пустых итераторов заранее не всегда возможно. В некоторых случаях из источника итератора можно догадаться, является ли он пустым - например, итераторы последовательностей и отображений пусты, если их родительский элемент имеет логическое значение false. Однако сами итераторы не имеют каких-либо указаний на содержимое и могут фактически быть «пустыми», если не повторены.

Единственным надежным способом является проверка, предоставляет ли итератор элементы при выполнении итерации . Можно определить итератор-обертку, который вызывает ошибку, если итератор вообще не предоставляет элементов.

def non_empty(iterable):
    """Helper to ensure that ``iterable`` is not empty during iteration"""
    iterator = iter(iterable)
    try:
        yield next(iterator)  # explicitly check first item
    except StopIteration:
        raise LookupError(f'{iterable} is empty') from None
    yield from iterator       # forward iteration of later items

Такой помощник может быть обернут как вокруг итераторов, так и итераторов и работает в явных циклах for 1012 * итераторов и любой другой итерационный сценарий.

>>> iterable = []
>>> for element in non_empty(iterable):
...    assert isinstance(element, int)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in non_empty
LookupError: [] is empty
1 голос
/ 04 февраля 2020

Вы можете использовать операторы и другие предложения для циклов .

L oop могут содержать предложение else; он выполняется, когда l oop завершается из-за исчерпания итерируемого.

Например:

iterator = []
for element in iterator:
    print('This wont print..')
else:
    assert iterator

Это приведет к:

Traceback (most recent call last):
  File "<pyshell#2>", line 4, in <module>
    assert iterator
AssertionError
...