groupby
迭代器返回分組函數結果的元組和一個綁定到運算符正在處理的相同「外部」迭代器的新迭代器。當您將dict()
應用到由groupby
返回的迭代器而不消耗此「內部」迭代器時,groupby
將不得不爲您推進「外部」迭代器。你必須認識到groupby
函數不會作用於一個序列,它會將任何這樣的序列轉換爲一個迭代器。
也許這可以用一些隱喻和handwaving更好地解釋。請隨着我們形成一個桶形線。
想象一下迭代器是一個人從井中抽水的人。他有無限數量的桶可供使用,但井可能是有限的。每次你向這個人詢問一桶水時,他都會從水井中抽出一個新水桶並傳給你。
在groupby
的情況下,您插入另一個人到您的萌芽桶鏈中。這個人根本沒有立即通過水桶。他向你傳遞了你給出的指示的結果,另外另一個人每次你要求一個桶時,只要它們與指令的結果相同,誰就會通過groupby
人將桶傳遞給任何人。如果說明的結果發生變化,則groupby
桶形傳送器將停止傳遞這些桶。所以well
給水桶groupby
,誰該傳遞給每個組的人,group A
,group B
,等等。
在您的例子中,水被編號,但只能有1000桶從井裏抽出。這是發生了什麼,當你再經過groupby
人到dict()
電話:
你dict()
電話詢問groupby
一個水桶。現在,groupby
要求井中人員提供一個桶,記住所給出的指示的結果,並保持在桶中。到dict()
他會通過指示的結果(False
)加上一個新的人,group A
。結果被存儲爲關鍵字,並且想要提取存儲桶的人被存儲爲值。此人是不尚未要求桶然而,因爲沒有人被要求它。
你dict()
電話詢問groupby
另一個桶。 groupby
有這些說明,並尋找結果改變的下一個桶。它仍然堅持到第一桶,沒有人要求它,所以它扔掉這桶。相反,它要求從井下一個桶並使用他的指示。結果與之前一樣,所以它也拋棄了這個新的水桶!更多的水流過地板,所以去下一個499桶。只有當編號爲501桶傳遞不結果的變化,所以現在groupby
找到另一個人下達指令(人group B
),新成果,True
一起,到dict()
傳遞這兩個。
您的dict()
致電店True
作爲鑰匙,而人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]
你的意思是「魔法師的學徒」?或者也許幻想曲有掃帚也拿水? – 2017-12-31 01:42:54
@ReblochonMasque魔法師的學徒[是幻想曲的一部分](https://en.wikipedia.org/wiki/Fantasia_%281940_film%29#Program)。 – 2017-12-31 15:01:50
好的,謝謝@MartijnPieters,我不知道。 – 2017-12-31 15:17:53