Python: итерация по непустому списку без предложения if получается пустой. Зачем? - PullRequest
4 голосов
/ 01 апреля 2009

Как итератор над непустой последовательностью, без фильтрации и агрегации (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 ]

13 голосов
/ 01 апреля 2009

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

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

>>> odd_integers_up_to_length('a').next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
4 голосов
/ 01 апреля 2009

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

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

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

0 голосов
/ 01 апреля 2009
>>> seq=['a','b','c']
>>> list((el,4) for el in seq)
[('a',4), ('b',4), ('c',4)]

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

0 голосов
/ 01 апреля 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...