如何生成通知并从函数返回结果?(Python)

如何生成通知并从函数返回结果?(Python),python,generator,yield,server-sent-events,Python,Generator,Yield,Server Sent Events,我必须创建一个函数,在内部调用中做一些艰苦的工作。此函数必须是生成器,因为我使用的是服务器发送的事件。因此,我希望这个函数通过使用“yield”来通知计算的进度。之后,此函数必须将结果传递给父函数,以便继续进行其他计算 我想要这样的东西: def hardWork(): for i in range(N): # hard work yield 'Work done: ' + str(i) # Here is the problem: I can'

我必须创建一个函数,在内部调用中做一些艰苦的工作。此函数必须是生成器,因为我使用的是服务器发送的事件。因此,我希望这个函数通过使用“yield”来通知计算的进度。之后,此函数必须将结果传递给父函数,以便继续进行其他计算

我想要这样的东西:

def hardWork():
    for i in range(N):
        # hard work
        yield 'Work done: ' + str(i)

    # Here is the problem: I can't return a result if I use a yield
    return result             

def generator():
    # do some calculations
    result = hardWork()
    # do other calculations with this result
    yield finalResult
def hardWork():
    for i in range(N):
        # hard work
        yield 'Work done so far: ' + str(i)

    # With this construction, you can still return a result after the `yield`s
    return result

def generator():
    # here's the new construction that makes it all work:
    result = yield from hardWork()

    # do other calculations with this result
    yield finalResult
我找到了一个解决方案,它包含一个字典,可以告诉我们函数是否完成了,但是执行此操作的代码非常脏

还有别的解决办法吗

谢谢大家!

编辑 我的想法是:

def innerFunction(gen):
    calc = 1

    for iteration in range(10):
        for i in range(50000):
            calc *= random.randint(0, 10)
        gen.send(iteration)

    yield calc


def calcFunction(gen):
    gen2 = innerFunction(gen)
    r = next(gen2)

    gen.send("END: " + str(r + 1))
    gen.send(None)


def notifier():
    while True:
        x = yield
        if x is None:
            return
        yield "Iteration " + x


def generator():
    noti = notifier()
    calcFunction(noti)
    yield from noti


for g in generator():
    print(g)
但我收到了这个错误:

TypeError: can't send non-None value to a just-started generator
Python3.5之前:生成器 此解决方案也适用于较新的Python版本,尽管Python3.5中新增的
async def
,似乎更适合您的用例。见下一节

生成器生成的值通过迭代或使用
next
获得。结束时返回的值存储在表示生成器结束的
StopIteration
异常的
value
属性中。幸运的是,恢复并不难

def hardWork():
    output = []

    for i in range(10):
        # hard work
        yield 'Doing ' + str(i)
        output.append(i ** 2)

    return output

def generator():
    # do some calculations
    work = hardWork()

    while True:
        try:
            print(next(work))
        except StopIteration as e:
            result = e.value
            break

    yield result
例子 输出 Python3.5+:
async def
如果您正在运行Python3.5+,那么您所尝试的似乎非常适合使用等待函数的事件循环

import asyncio

async def hardWork():
    output = []

    for i in range(10):
        # do hard work
        print('Doing ', i)
        output.append(i**2)

        # Break point to allow the event loop to do other stuff on the side
        await asyncio.sleep(0)

    return output

async def main():
    result = await asyncio.wait_for(hardWork(), timeout=None)
    print(result)

loop = asyncio.get_event_loop()

loop.run_until_complete(main())
输出
我的建议是将您的功能嵌入到类中

def Worker:

    def hardWork(self):
        self.Finished = False
        for i in range(10):
            yield 'Work done: ' + str(i)
        self.Finished = True
        self.Result = 'result'

    def generator(self):
        while (not self.Finished):
            print(next(self.hardWork()))
        return self.Result
这将具有您想要的功能,而不必担心围绕异常抛出捕获逻辑编程您的逻辑。

Python 3.3介绍了这一点,这正是您想要的
yield from
允许主生成器将功能委托给另一个函数,该函数也包含
yield
语句,如下所示:

def hardWork():
    for i in range(N):
        # hard work
        yield 'Work done: ' + str(i)

    # Here is the problem: I can't return a result if I use a yield
    return result             

def generator():
    # do some calculations
    result = hardWork()
    # do other calculations with this result
    yield finalResult
def hardWork():
    for i in range(N):
        # hard work
        yield 'Work done so far: ' + str(i)

    # With this construction, you can still return a result after the `yield`s
    return result

def generator():
    # here's the new construction that makes it all work:
    result = yield from hardWork()

    # do other calculations with this result
    yield finalResult

请看这个问题:我认为您应该真正了解异步函数,因为这与您正在做的非常接近
def hardWork():
    for i in range(N):
        # hard work
        yield 'Work done so far: ' + str(i)

    # With this construction, you can still return a result after the `yield`s
    return result

def generator():
    # here's the new construction that makes it all work:
    result = yield from hardWork()

    # do other calculations with this result
    yield finalResult