首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重用生成器表达式

重用生成器表达式
EN

Stack Overflow用户
提问于 2018-03-23 10:24:18
回答 3查看 1.2K关注 0票数 7

生成器表达式是一个非常有用的工具,与列表理解相比,它有一个巨大的优势,即它不为一个新数组分配内存。

生成器表达式的问题是,我只能使用这样的生成器一次,这最终使我不得不编写列表理解:

代码语言:javascript
复制
>>> names = ['John', 'George', 'Paul', 'Ringo']
>>> has_o = (name for name in names if 'o' in name)
>>> for name in has_o:
...   print(name.upper())
...
JOHN
GEORGE
RINGO
>>> for name in has_o:
...   print(name.lower())
...
>>>

上面的代码说明了生成器表达式如何只能使用一次。当然,这是因为生成器表达式返回--生成器的实例,而不是定义一个可以一次又一次实例化的生成器函数。

是否有一种方法可以在每次使用生成器时复制它,以便使其可重用,或者使生成器表达式语法返回生成器函数而不是单个实例?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-03-23 10:27:43

让它成为lambda

代码语言:javascript
复制
has_o = lambda names: (name for name in names if 'o' in name)
for name in has_o(["hello","rrrrr"]):
   print(name.upper())
for name in has_o(["hello","rrrrr"]):
   print(name.upper())

lambda是一个一行,每次返回一个新的生成器.在这里,我选择能够传递输入列表,但是如果它是固定的,您甚至不需要参数:

代码语言:javascript
复制
names = ["hello","rrrrr"]
has_o = lambda: (name for name in names if 'o' in name)
for name in has_o():
   print(name.upper())
for name in has_o():
   print(name.upper())

在最后一种情况下,请注意这样一个事实:如果names更改或重新分配,lambda将使用新的names对象。您可以通过使用默认值技巧来修复名称重新分配:

代码语言:javascript
复制
has_o = lambda lst=names: (name for name in lst if 'o' in name)

您还可以通过使用默认值和复制技巧(当您认为您的第一个目标是避免创建一个列表:)时,可以修复names的事后修改:

代码语言:javascript
复制
has_o = lambda lst=names[:]: (name for name in lst if 'o' in name)

(现在做出选择:)

票数 9
EN

Stack Overflow用户

发布于 2018-03-23 10:28:09

itertools.tee允许您从一个迭代器中生成多个迭代器:

代码语言:javascript
复制
from itertools import tee

names = ['John', 'George', 'Paul', 'Ringo']
has_o_1, has_o_2 = tee((name for name in names if 'o' in name), 2)
print('iterable 1')
for name in has_o_1:
    print(name.upper())
print('iterable 2')
for name in has_o_2:
    print(name.upper())

输出:

代码语言:javascript
复制
iterable 1
JOHN
GEORGE
RINGO
iterable 2
JOHN
GEORGE
RINGO
票数 2
EN

Stack Overflow用户

发布于 2019-07-13 17:25:09

好了,各位,下面是一段代码,可以使迭代器可重用。每次迭代之后,它会自动重置自己,所以您不必担心任何事情。它的效率有多高,嗯,它是两个方法调用( tee()的一个next(),它反过来调用迭代器本身的next() )和一个try-除了在原始迭代器之上的额外块。您必须决定一个微小的速度损失是否可以,或者使用lambda重建迭代器,如其他答案所示。

代码语言:javascript
复制
from itertools import tee

class _ReusableIter:
    """
    This class creates a generator object that wraps another generator and makes it reusable
    again after each iteration is finished.
    It makes two "copies" (using tee()) of an original iterator and iterates over the first one.
    The second "copy" is saved for later use.
    After first iteration reaches its end, it makes two "copies" of the saved "copy", and
    the previous iterator is swapped with the new first "copy" which is iterated over while the second "copy" (a "copy" of the old "copy") waits for the
    end of a new iteration, and so on.
    After each iteration, the _ReusableIter() will be ready to be iterated over again.

    If you layer a _ReusableIter() over another _ReusableIter(), the result can lead you into an indefinite loop,
    or provoke some other unpredictable behaviours.
    This is caused by later explained problem with copying instances of _ReusableIter() with tee().
    Use ReusableIterator() factory function to initiate the object.
    It will prevent you from making a new layer over an already _ReusableIter()
    and return that object instead.

    If you use the _ReusableIter() inside nested loops the first loop
    will get the first element, the second the second, and the last nested loop will
    loop over the rest, then as the last loop is done, the iterator will be reset and
    you will enter the infinite loop. So avoid doing that if the mentioned behaviour is not desired.

    It makes no real sense to copy the _ReusableIter() using tee(), but if you think of doing it for some reason, don't.
    tee() will not do a good job and the original iterator will not really be copied.
    What you will get instead is an extra layer over THE SAME _ReusableIter() for every copy returned.

    TODO: A little speed improvement can be achieved here by implementing tee()'s algorithm directly into _ReusableIter()
    and dump the tee() completely.
    """
    def __init__ (self, iterator):
        self.iterator, self.copy = tee(iterator)
        self._next = self.iterator.next

    def reset (self):
        self.iterator, self.copy = tee(self.copy)
        self._next = self.iterator.next

    def next (self):
        try:
            return self._next()
        except StopIteration:
            self.reset()
            raise

    def __iter__ (self):
        return self

def ReusableIter (iterator):
    if isinstance(iterator, _ReusableIter):
        return iterator
    return _ReusableIter(iterator)

Usage:
>>> names = ['John', 'George', 'Paul', 'Ringo']
>>> has_o = ReusableIter(name for name in names if 'o' in name)
>>> for name in has_o:
>>>     print name
John
George
Ringo
>>> # And just use it again:
>>> for name in has_o:
>>>     print name
John
George
Ringo
>>>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49447447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档