Python 有没有办法把这台发电机弄干?

Python 有没有办法把这台发电机弄干?,python,python-3.x,iterator,generator,dry,Python,Python 3.x,Iterator,Generator,Dry,下面的方法在我的类中,在完成其工作之前尝试初始化它自己。primer在做它的工作时非常懒惰,就像它后面的处理循环一样。在这两个循环中重复了五行,我不清楚消除重复的最佳方法是什么 @classmethod def __get_start_words(cls, iterable, n, start_words): iterator, buffer, sentinel = iter(iterable), Deque(maxlen=n), object() for _ in range(

下面的方法在我的类中,在完成其工作之前尝试初始化它自己。primer在做它的工作时非常懒惰,就像它后面的处理循环一样。在这两个循环中重复了五行,我不清楚消除重复的最佳方法是什么

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    iterator, buffer, sentinel = iter(iterable), Deque(maxlen=n), object()
    for _ in range(n):
        item = next(iterator, sentinel)
        if item is sentinel:
            # raise ValueError('iterable was too short to satisfy n')
            break
        buffer.append(item)
        yield item
    start_words[buffer.prefix] += 1
    while True:
        if buffer[0][-1] in cls.TERMINATORS:
            start_words[buffer.suffix] += 1
        item = next(iterator, sentinel)
        if item is sentinel:
            break
        buffer.append(item)
        yield item
有没有一种有效而清晰的方法,在课堂或方法中只写一次最后五行

附录

关于前缀和后缀是什么的问题,这里是Deque类的答案:

第二版

在考虑了其他人的意见后,为了提高效率,编写了以下方法:

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    iterator, buffer, count = iter(iterable), Deque(maxlen=n), 0
    for item, count in zip(iterator, range(n)):
        buffer.append(item)
        yield item
    if count + 1 < n:
        raise ValueError('iterable was too short to satisfy n')
    start_words[buffer.prefix] += 1
    try:
        while True:
            if buffer[0][-1] in cls.TERMINATORS:
                start_words[buffer.suffix] += 1
            item = next(iterator)
            buffer.append(item)
            yield item
    except StopIteration:
        pass
第三版

该方法的第三个版本改编自的富有洞察力的答案:

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    count, buffer = 0, Deque(maxlen=n)
    for count, item in enumerate(iterable, 1):
        yield item
        buffer.append(item)
        if count == n:
            start_words[buffer.prefix] += 1
        if count >= n and buffer[0][-1] in cls.TERMINATORS:
            start_words[buffer.suffix] += 1
    if count < n:
        raise ValueError('iterable was too short to satisfy n')
最终版本

这个方法比我的第一个版本要好得多——感谢在这里帮助我的人

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    buffer = Deque(maxlen=n)
    for count, item in enumerate(iterable, 1):
        yield item
        buffer.append(item)
        if count == n:
            start_words[buffer.prefix] += 1
        if count >= n and buffer[0][-1] in cls.TERMINATORS:
            start_words[buffer.suffix] += 1
    if len(buffer) < n:
        raise ValueError('iterable was too short to satisfy n')
用于循环:

进一步的重构导致:

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    iterable = iter(iterable)
    buffer = deque(islice(iterable, n-1))
    yield from buffer
    if len(buffer) < n - 1:
        raise ValueError('iterable was too short to satisfy n')
    start_words[tuple(buffer)] += 1
    for item in iterable:
        buffer.append(item)
        yield item
        first = buffer.popleft()
        if first[-1] in cls.TERMINATORS:
            start_words[tuple(buffer)] += 1
用于循环:

进一步的重构导致:

@classmethod
def __get_start_words(cls, iterable, n, start_words):
    iterable = iter(iterable)
    buffer = deque(islice(iterable, n-1))
    yield from buffer
    if len(buffer) < n - 1:
        raise ValueError('iterable was too short to satisfy n')
    start_words[tuple(buffer)] += 1
    for item in iterable:
        buffer.append(item)
        yield item
        first = buffer.popleft()
        if first[-1] in cls.TERMINATORS:
            start_words[tuple(buffer)] += 1

顺便说一句,什么是buffer.prefix和buffer.suffix?我决定在第一个循环中进行逻辑检查,如果合适的话,可以引发一个异常。如果更改使问题无效,我会很高兴地将其删除。对于SE来说,可能是一个更好的问题:codereviewWhy不是您的for循环,只针对iterable中的项目:?@RobertB我认为最好将初级处理器和处理器明确分开。顺便说一句,什么是buffer.prefix和buffer.suffix?我决定在第一个循环中进行逻辑检查,如果合适的话,会引发一个异常。如果更改使问题无效,我会很高兴地将其删除。对于SE来说,这可能是一个更好的问题:codereviewWhy不是您的for循环,只针对iterable中的项目:?@RobertB我认为最好将初级处理器和处理器明确分开。谢谢您的建议!查看代码后,我意识到应该进行一些错误检查,并通过引发异常而不是中断来更改第一个循环。您是否介意将您已经写得很好的答案修改为例外情况?如果您认为没有理由更改我的代码以进行改进,因为它被修改为引发异常,没有理由将其晾干,请让我知道,我将把代码还原为使用break,而不是像以前那样使用raise。@noctiskytower这基本上就是我的方法。看起来您只是尝试使用自定义的raise-StopIteration方法复制for循环。您的解决方案在for循环的最后两行中没有问题吗?迭代器耗尽后,第二个while循环的前两行再次运行。您的循环似乎没有这样做。因此不需要在问题末尾添加我的方法的第二个版本?我想我已经开始了解循环中最后两条处理行的执行方式与我的完全相同。让我困惑的是他们被感动了;但是在功能上,他们还是像以前一样被执行。谢谢你的建议!查看代码后,我意识到应该进行一些错误检查,并通过引发异常而不是中断来更改第一个循环。您是否介意将您已经写得很好的答案修改为例外情况?如果您认为没有理由更改我的代码以进行改进,因为它被修改为引发异常,没有理由将其晾干,请让我知道,我将把代码还原为使用break,而不是像以前那样使用raise。@noctiskytower这基本上就是我的方法。看起来您只是尝试使用自定义的raise-StopIteration方法复制for循环。您的解决方案在for循环的最后两行中没有问题吗?迭代器耗尽后,第二个while循环的前两行再次运行。您的循环似乎没有这样做。因此不需要在问题末尾添加我的方法的第二个版本?我想我已经开始了解循环中最后两条处理行的执行方式与我的完全相同。让我困惑的是他们被感动了;但在功能上,他们仍然像以前一样被处决。
for item in islice(iterator, n):
    buffer.append(item)
    yield item
if len(buffer) < n:
    raise ValueError('iterable was too short to satisfy n')
@classmethod
def __get_start_words(cls, iterable, n, start_words):
    iterable = iter(iterable)
    buffer = deque(islice(iterable, n-1))
    yield from buffer
    if len(buffer) < n - 1:
        raise ValueError('iterable was too short to satisfy n')
    start_words[tuple(buffer)] += 1
    for item in iterable:
        buffer.append(item)
        yield item
        first = buffer.popleft()
        if first[-1] in cls.TERMINATORS:
            start_words[tuple(buffer)] += 1