2009-03-31 6 views
4

Как итератор по непустой последовательности без фильтрации и без агрегации (sum() и т. Д.) Ничего не дает?Python: итерация по непустому списку без if-clause становится пустой. Зачем?

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

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 объектов, не так ли? Что происходит?

+0

Wow ... вы вообще связали с hekevintran (http://stackoverflow.com/users/84952/hekevintran)? Задайте вопрос. Ответьте на это почти сразу. –

+0

Неужели это плохая вещь? Я просто делился своим наблюдением в форме вопроса, как и с the FAQ: «Также прекрасно спросить и ответить на свой собственный вопрос программирования, но притворяйтесь, что вы находитесь под угрозой: произнесите его в форме вопроса». –

+0

My n00b warts покажут :) ... эта ссылка должна быть http://stackoverflow.com/faq, конечно, –

ответ

13

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

взгляд на первой итерации, когда значение «а»:

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

К сожалению, я должен был сказать, что я просто публиковал наблюдение в форме вопроса - извините, я потратил ваше время без нужды! –

4

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

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

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

0

ул зарезервированное keword, вы должны назвать переменную по-разному

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

+0

Истинный :), это было просто брошено вместе для примера здесь. –

+1

Терминология nitpick: не зарезервированное ключевое слово (или оно не будет компилироваться) - это встроенный инструмент, который хорошо не тень. – Brian

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

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