Python中产量问题|使用辅助函数

时间:2017-05-04 14:01:21

标签: python python-3.x generator yield

给定一个包含许多单词的字符串,我想颠倒单词的顺序。如果输入为Thanks for all the fish,则输出应为fish the all for Thanks

我尝试使用生成器解决此问题,以避免创建新列表。 我提出了以下解决方案:

from itertools import islice

def foo(s, begin, end):
    for elem in islice(s, begin, end):
        yield elem

def baz(s):
    i = len(s)
    j = len(s)

    while True:
        i -= 1
        if i == -1:
            foo(s, i+1, j)
            break
        if s[i] == ' ':
            foo(s, i+1, j)
            yield ' '
            j = i


s = "Thanks for all the fish"
g = baz(s)
for x in g: print(x, end='')

但是,此代码的输出为" "(仅包含空格的字符串)。

另一方面,如果我直接print元素而不是产生它们,它就可以了:

from itertools import islice

def foo(s, begin, end):
    for elem in islice(s, begin, end):
        print(elem, end='')

def baz(s):
    i = len(s)
    j = len(s)

    while True:
        i -= 1
        if i == -1:
            foo(s, i+1, j)
            break
        if s[i] == ' ':
            foo(s, i+1, j)
            print(' ', end='')
            j = i


s = "Thanks for all the fish"
g = baz(s)

这可以作为输出fish the all for Thanks。但我不想只是打印它,我想要一个正确的发电机。

最后,我发现如果避免调用foo,它也会起作用:

from itertools import islice

def baz(s):
    i = len(s)
    j = len(s)

    while True:
        i -= 1
        if i == -1:
            for elem in islice(s, i+1, j):
                yield elem
            break
        if s[i] == ' ':
            for elem in islice(s, i+1, j):
                yield elem
            yield ' '
            j = i


s = "Thanks for all the fish"
g = baz(s)
for x in g: print(x, end='')

此输出为fish the all for Thanks。 这个版本给了我想要的东西(一个正确的生成器),但我在其函数内重复代码。

我重新讨论了关于收益率的堆栈交换线程,但我可能已经理解错了。 我所理解的是,生成器将一直运行,直到找到下一个yield语句(或函数结束)。 这个问题让我觉得这不是它的确切运作方式,但除此之外,我一无所知。

如何使用第一个代码段中的辅助函数解决此问题?

1 个答案:

答案 0 :(得分:2)

您可以使用yield from foo(...)(另请参阅PEP-380 on "Syntax for Delegating to a Subgenerator")或for whatever in foo(...): yield whatever来成功yield来自生成器的元素:

def baz(s):
    i = len(s)
    j = len(s)

    while True:
        i -= 1
        if i == -1:
            yield from foo(s, i+1, j)    # yield from syntax
            break
        if s[i] == ' ':
            for item in foo(s, i+1, j):  # for-loop over generator
                yield item
            yield ' '
            j = i

但是,正如@trentcl在评论中指出的那样,在你的情况下你不需要foo - 帮助函数,因为它基本上也是islice所做的。因此,您只需将foo替换为islice

即可
def baz(s):
    i = len(s)
    j = len(s)

    while True:
        i -= 1
        if i == -1:
            yield from islice(s, i+1, j)    # yield from syntax
            break
        if s[i] == ' ':
            for item in islice(s, i+1, j):  # for-loop over generator
                yield item
            yield ' '
            j = i