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
доставляет вам неприятности здесь...