РЕДАКТИРОВАТЬ : Используйте itertools.islice
.Приведенный ниже шаблон, предложенный мною, является плохой идеей - он падает, когда it
дает менее n
значений, и это поведение зависит от тонких проблем, поэтому люди, читающие такой код, вряд ли поймут его точную семантику.
Существует также
[next(it) for _ in range(n)]
, который может (?) Быть более понятным для людей, не знакомых с itertools;но если вы много работаете с итераторами, itertools является достойным дополнением к вашему набору инструментов.
Что произойдет, если next(it)
был исчерпан и вызовет StopIteration
?
(т.е. когдаit
имел меньше чем n
значений, чтобы получить)
Когда я писал вышеупомянутую строку пару лет назад, я, вероятно, думал, что StopIteration
будет иметь умный побочный эффект от чистого прекращения понимания списка.Но нет, все понимание рухнет, пройдя StopIteration
вверх.(Он будет завершен без ошибок, только если исключение возникло из итератора range(n)
.)
Это, вероятно, не то поведение, которое вам нужно.
Но оно ухудшается.Следующее должно быть эквивалентно пониманию списка (особенно в Python 3):
list(next(it) for _ in range(n))
Это не так.Внутренняя часть является сокращением для функции генератора;list()
знает, что это сделано, когда оно вызывает StopIteration
в любом месте .
=> Эта версия благополучно справляется, когда нет n
значений, и возвращает более короткий список.(Как itertools.islice()
.)
[Казни: 2,7 , 3,4 ]
Но это тоже изменится!Тот факт, что генератор молча завершает работу, когда любой код внутри него поднимает StopIteration
, является известной бородавкой, адресуемой PEP 479 .Начиная с Python 3.7 (или 3.5 с будущим импортом), это вызовет RuntimeError
вместо чистой доработки генератора.Т.е. это станет похоже на поведение понимания списка.(Проверено на последней сборке HEAD)