Python: итерация по непустому списку без предложения if получается пустой. Зачем?

Как можно итератор над непустой последовательностью, без фильтрации и без агрегации (sum()и т. д.), ничего не дают?

Рассмотрим простой пример:

sequence = ['a', 'b', 'c']
list((el, ord(el)) for el in sequence)

Это дает [('a', 97), ('b', 98), ('c', 99)] как и ожидалось.

Теперь просто поменяйте ord(el) для выражения, которое берет первое значение из некоторого генератора, используя (...).next() - простите надуманный пример:

def odd_integers_up_to_length(str):
    return (x for x in xrange(len(str)) if x%2==1)

list((el, odd_integers_up_to_length(el).next()) for el in sequence)

Это дает [], Да, пустой список нет ('a',материал) кортежи. Ничего такого.

Но мы не фильтруем, не агрегируем и не сокращаем. Генераторное выражение над n объекты без фильтрации или агрегации должны давать n объекты, верно? В чем дело?

4 ответа

Решение

odd_integers_up_to_length(el).next() вызовет StopIteration, которое не поймано там, но поймано для выражения генератора в нем, останавливая его, ничего не давая.

посмотрим на первую итерацию, когда значение равно 'a':

>>> odd_integers_up_to_length('a').next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Что происходит, так это то, что next() вызов поднимает StopIteration исключение, которое помещает стек в выражение внешнего генератора и останавливает эту итерацию.

StopIteration нормальный способ для итератора сигнализировать, что это сделано. Обычно мы этого не видим, потому что обычно next() вызов происходит внутри конструкции, которая использует итератор, например for x in iterator или же sum(iterator), Но когда мы звоним next() непосредственно мы несем ответственность за StopIteration, Невыполнение этого требования приводит к утечке в абстракции, что приводит к неожиданному поведению во внешней итерации.

Урок, я полагаю: будьте осторожны с прямыми звонками next(),

str является зарезервированным ключом, вы должны называть свою переменную по-другому

Я должен был также сообщить о следующем

>>> seq=['a','b','c']
>>> list((el,4) for el in seq)
[('a',4), ('b',4), ('c',4)]

Так что это не list доставляет вам неприятности здесь...

Другие вопросы по тегам