这没有意义——“迭代器返回函数”变成“可迭代返回函数”。如果一个函数正在返回一个迭代器,那么它已经返回了一个迭代器,因为迭代器是迭代器,因为它们需要有__iter__ 方法。
来自the docs:
可迭代
一个能够一次返回其成员的对象。示例
可迭代对象包括所有序列类型(例如 list、str 和 tuple)
以及一些非序列类型,如字典、文件对象和
您使用__iter__() 或__getitem__() 方法定义的任何类。
Iterables 可用于 for 循环和许多其他地方
需要序列(zip(),map(),...)。当一个可迭代对象是
作为参数传递给内置函数 iter(),它返回一个
对象的迭代器。此迭代器适用于一次通过
一组值。使用可迭代对象时,通常不需要
调用 iter() 或自己处理迭代器对象。 for 语句
自动为您执行此操作,创建一个临时的未命名变量
在循环期间保持迭代器。另见迭代器,
序列和生成器。
迭代器
表示数据流的对象。反复调用
迭代器的__next__() 方法(或将其传递给内置函数
next()) 返回流中的连续项目。当没有更多数据时
而是引发了一个 StopIteration 异常。在此刻,
迭代器对象已用尽并且对其的任何进一步调用
__next__() 方法只是再次引发 StopIteration。
迭代器必须有一个 __iter__() 方法,该方法返回迭代器对象本身,因此每个迭代器也是可迭代的
并且可以在大多数接受其他迭代的地方使用。一
值得注意的例外是尝试多次迭代的代码。一种
容器对象(例如列表)每个生成一个新的迭代器
将它传递给 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)]
上述两种方法都可能占用大量内存,因此有时这不是一个选择。在这种情况下,您找到的解决方案将运作良好。另一个我能想到的实现,它更面向对象,但与你的没有太大区别:
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)]