它沒有任何意義 - 「迭代器返回函數」到「可迭代返回函數」。如果一個函數返回一個迭代器,那麼它已經返回一個迭代器,因爲迭代器是迭代器,因爲它們需要有__iter__
方法。
從the docs:
迭代
能夠一次返回其成員的一個的目的。 迭代示例包括您使用__iter__
()或__getitem__
()方法定義的任何類的所有序列類型(如list,str和元組) 以及某些非序列類型(如字典,文件對象和 )。 可以在for循環中以及需要 序列(zip(),map(),...)的許多其他地方使用應用程序。當一個可迭代對象 作爲參數傳遞給內建函數iter()時,它將返回該對象的一個 迭代器。此迭代器適用於通過 值集的一次傳遞。在使用迭代器時,通常不需要調用iter()或自己處理迭代器對象。for語句 會爲您自動執行此操作,從而創建臨時未命名變量 以在循環的持續時間內保存迭代器。另請參閱迭代器, 序列和發生器。
迭代
表示數據流的對象。重複調用 迭代器的__next__
()方法(或將它傳遞給內置函數 next())將返回流中的連續項。當沒有更多的數據可用時,則會引發StopIteration異常。此時,迭代器對象已耗盡,並且任何進一步調用其方法 ()方法都會再次引發StopIteration。
迭代器都要求有一個返回迭代器對象本身的__iter__
()方法,以便每個迭代器也可迭代
,並且可以在其他iterables被接受的大多數地方使用。一個 值得注意的例外是嘗試多次迭代過程的代碼。 A容器對象(例如列表)產生一個新的迭代器,每個迭代器將其傳遞給iter()函數或在for循環中使用它。 使用迭代器嘗試執行此操作將返回與先前迭代過程中使用的迭代器對象相同的耗盡 ,使其看起來像空容器一樣顯示爲 。
UPD:
我的意思是......
案例1(按步驟比較顯示):
f = to_iterable_maker(iterator_maker)
;
i = f(some_var)
,i
是nonce_iterable
與__iter__
;
j = iter(i)
,j
是由iterator_maker(some_var)
返回的迭代器;
next(j)
,返回一些值取決於some_var
。
案例2:
f = iterator_maker
;
i = f(some_var)
,i
是等於iterator_maker(some_var)
的迭代器,其具有__iter__
(每迭代器協議);
j = iter(i)
,j
是迭代器iterator_maker(some_var)
返回,因爲迭代器調用__iter__
返回本身,所以j is i
回報true
;
next(j)
,返回一些值取決於some_var
。
正如您所看到的,除了準備步驟中的其他複雜情況外,沒有什麼變化。
也許你可以提供關於你想通過這樣的'包裝'來實現什麼的額外信息,以瞭解真正的問題。
根據你的問題,我不能想到任何庫函數,這將把迭代器變成可迭代的,因爲它已經是了。如果你想重複迭代器,可以看看itertools.tee()
。
UPD2:
所以,現在我明白了,我們的目標是轉換單通迭代多遍迭代器...
我的回答:
「標準庫已經提供了類似於 to_iterable_maker的東西嗎?」
是「否」。但最接近的是itertools.tee()
,它可以幫助你將單個迭代器克隆成幾個,你可以在之後使用。關於你提到的例子:
import itertools
base = range(3)
poops_out = itertools.permutations(base)
iterators = itertools.tee(poops_out, 4)
#You shouldn't use original iterator after clonning, so make it refer to a clone
#to be used again, otherwise ignore the following line
poops_out, iterators = iterators[0], iterators[1:]
for it in iterators:
print list(it)
#Prints:
#[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
#[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
#[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
另一種常見的方式從迭代器獲取迭代是使用list()
或tuple()
將它轉換,這將使多道:
import itertools
base = range(3)
poops_out = itertools.permutations(base)
#Obviously poops_out gets consumed at the next line, so it won't iterate anymore
keeps_going = tuple(poops_out)
print list(poops_out)
# []
print list(poops_out)
# []
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
上述兩種方法都可能是沉重的內存使用情況,所以有時候這不是一個選項。在這種情況下,您遇到的解決方案將運行良好。另一個implemetation,這是我能想到的,並且是多一點點的面向對象的,但在其他方面沒有太大的不同,你的:
class IterableMaker(object):
'''Wraps function returning iterator into "proper" iterable'''
def __init__(self, iterator_maker):
self.f = iterator_maker
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def __iter__(self):
return self.f(*self.args, **self.kwargs)
使用是一樣的:
import itertools
class IterableMaker(object):
def __init__(self, iterator_maker):
self.f = iterator_maker
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def __iter__(self):
return self.f(*self.args, **self.kwargs)
base = range(3)
poops_out = itertools.permutations(base)
print list(poops_out)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
print list(poops_out)
# []
my_perm = IterableMaker(itertools.permutations)
keeps_going = my_perm(base)
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
print list(keeps_going)
# [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
你似乎困惑,python中的所有迭代器都是可迭代的。 '__iter__'方法是一個身份函數的事實並不重要。你是否試圖創建一個迭代器,它可以多次迭代**? – ppperry
是否有一個具體的問題,你試圖解決這個問題? – jonrsharpe
您的「可迭代製造商」將一遍又一遍地調用原始迭代器。另外,也許你可以使用['itertools.tee'](https://docs.python.org/3/library/itertools.html#itertools.tee)? –