Итератор groupby
возвращает наборы результатов функции группировки и новый итератор, связанный с тем же «внешним» итератором, над которым работает оператор groupby
. Когда вы применяете dict()
к итератору, возвращенному groupby
, не потребляя этот «внутренний» итератор, groupby
должен будет продвинуть «внешний» итератор за вас. Вы должны понимать, что функция groupby
не действует на последовательность, она превращает любую такую последовательность в итератор для вас.
Возможно, это лучше объяснить некоторыми метафорами и рукопожатием. Пожалуйста, следуйте, пока мы формируем линию ведра.
Представьте себе итераторов как человека, который черпает воду в ведрах из колодца. У него есть неограниченное количество ведер для использования, но колодец может быть конечным. Каждый раз, когда вы просите у этого человека ведро с водой, он достает из колодца с водой новое ведро и передает его вам.
В случае groupby
вы вставляете другого человека в свою начинающую цепочку ведер. Этот человек не сразу передает ведра вообще. Он передает вам результат инструкций, которые вы ему дали, плюс другого человека каждый раз, когда вы просите ведро, который затем передает вам ведра через человека groupby
тому, кто спрашивает, при условии, что они соответствуют тот же результат в инструкции. groupby
Проходчик сегментов прекратит передачу этих интервалов, если результат выполнения команд изменится. Так что well
дает ведра для groupby
, который передает это человеку по группе, group A
, group B
и т. Д.
В вашем примере вода пронумерована, но из колодца можно извлечь только 1000 ведер. Вот что происходит, когда вы затем передаете groupby
человека на dict()
вызов:
Ваш dict()
звонок просит groupby
за ведро. Теперь groupby
просит одного ведра у человека в колодце, запоминает результат выполнения данных инструкций, держась за ведро. На dict()
он передаст результат инструкции (False
) плюс новый человек, group A
. Результат сохраняется в качестве ключа, а group A
человек, который хочет вытащить ведра, сохраняется в качестве значения. Этот человек не все же просит о ведрах, потому что никто не просит его .
Ваш dict()
звонок запрашивает groupby
другое ведро. groupby
имеет эти инструкции и отправляется на поиски следующего сегмента, где меняется результат. Он все еще держался за первое ведро, никто его не просил, поэтому он выбрасывает это ведро. Вместо этого он просит следующее ведро из скважины и использует его инструкции. Результат тот же, что и раньше, поэтому он выбрасывает и это новое ведро! Больше воды течет по полу, и поэтому идут следующие 499 ведер. Только когда пропущен сегмент с номером 501, результат изменяется, поэтому теперь groupby
находит другого человека, который дает инструкции (person group B
), вместе с новым результатом, True
, передавая эти два значения dict()
.
Ваш dict()
вызов сохраняет True
в качестве ключа, а person group B
в качестве значения. group B
ничего не делает, никто не просит воды.
Ваш dict()
просит другое ведро. groupby
проливает больше воды, пока в нем не окажется ведро с номером 999, и человек у колодца пожимает плечами и заявляет, что теперь колодец пуст. groupby
говорит dict()
колодец пуст, больше нет ведер, может, он перестанет спрашивать. Он по-прежнему удерживает ведро с номером 999, потому что ему никогда не нужно освободить место для следующего ведра из скважины.
Теперь вы идете и спрашиваете dict()
о том, что связано с ключом True
, то есть лицом group B
. Вы передаете group B
на list()
, и поэтому group B
запрашивает все корзины group B
. group B
восходит к groupby
, который держит только одну корзину, корзину с номером 999, и результат инструкций для этой корзины соответствует тому, что ищет group B
. Итак, это одно ведро group B
дает list()
, затем пожимает плечами, потому что больше нет ведер, потому что groupby
сказал ему об этом.
Затем вы спрашиваете dict()
о человеке, связанном с ключом False
, который является человеком group A
.К настоящему времени groupby
больше нечего дать, колодец сухой, и он стоит в луже 999 ведер воды с числами, плавающими вокруг.Ваш второй list()
ничего не получает.
Мораль этой истории?Немедленно попросите все ведра воды, когда говорите с groupby
, потому что он разлит их всех, если вы этого не сделаете!Итераторы подобны метлам в фантазии, старательно перемещая воду без понимания, и вам лучше надеяться, что у вас кончится вода, если вы не знаете, как их контролировать.
Вот код, который будет делать то, что вы ожидаете (снемного меньше воды, чтобы предотвратить затопление):
>>> from itertools import groupby
>>> keyfunc = lambda x : x > 5
>>> obj = dict((k, list(v)) for k, v in groupby(range(10), keyfunc))
>>> obj(True)
[0, 1, 2, 3, 4, 5]
>>> obj(False)
[6, 7, 8, 9]