为避免混淆,让我定义:
正确的可迭代:一个不是迭代器的可迭代对象。
问: Python的标准库是否已经提供了将“迭代器返回函数”转换为“正确的可迭代 - 返回函数”的方法?
我以为我在某个地方见过这个,但现在我找不到了。特别是,我浏览了itertools
的文档,但没有发现它。
FWIW,这个本土的实现似乎有效:
def to_iterable_maker(iterator_maker):
def iterable_maker(*args, **kwargs):
class nonce_iterable(object):
def __iter__(self):
return iterator_maker(*args, **kwargs)
return nonce_iterable()
return iterable_maker
...但那里的一次性nonce_iterable
课对我来说看起来很笨拙。我确信从标准库中实现这样的事情会好得多。
@Nikita
试试这个:
import itertools
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)
# []
myperms = to_iterable_maker(itertools.permutations)
keeps_going = myperms(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)]
是 itertools.permutations
和to_iterable_maker(itertools.permutations)
返回的值之间的差异。我的问题是:标准库是否已提供与to_iterable_maker
类似的内容?
答案 0 :(得分:0)
它没有意义 - "迭代器返回功能"进入一个可迭代的返回函数"。如果一个函数返回一个迭代器,那么它已经返回一个iterable,因为迭代器是迭代的,因为它们需要__iter__
方法。
来自the docs:
<强>迭代强>
一个能够一次返回一个成员的对象。示例 iterables包括所有序列类型(例如list,str和tuple) 和一些非序列类型,如dict,文件对象和对象 您使用
__iter__
()或__getitem__
()方法定义的任何类。 Iterables可用于for循环和许多其他地方 需要序列(zip(),map(),...)。当可迭代对象是 作为参数传递给内置函数iter(),它返回一个 对象的迭代器。这个迭代器很适合一次通过 一组价值观。使用iterables时,通常没有必要 调用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
; < / LI>
next(j)
,返回一些取决于some_var
的值。正如您所看到的,除了准备步骤中的其他复杂情况外,没有任何改变。
可能您可以通过此类&#39;包装来提供有关您尝试实现的内容的其他信息,以了解真正的问题。
根据你的问题,我无法想到任何库函数,它会将迭代器变成可迭代的,因为它已经是。如果您尝试复制迭代器,可以查看itertools.tee()
。
<强> UPD2 强>:
所以,现在我看到,目标是将单通道迭代器转换为多通道迭代器...
我的回答:
&#34;标准库是否已提供类似的内容 to_iterable_maker&#34;
是&#34;否&#34;。但最接近的是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)]