检测python coroutine称为子例程

时间:2015-08-17 14:46:08

标签: python coroutine

我们说我有一堆协同程序。应使用yield from调用这些协同程序。我怎么能检测到我犯了一个错误并像子程序一样直接调用了协程?

以下是一个示例代码:

import asyncio

@asyncio.coroutine
def A(msg):
    print(msg)
    yield from asyncio.sleep(1)

@asyncio.coroutine
def B():
    while True :
        yield from A('1')
        A('2')
        yield from A('3')

loop = asyncio.get_event_loop()
loop.run_until_complete(B())

输出:

1
3
1
3
1
3
...

调用coroutine就像子例程一样,但不会引发异常或阻塞事件循环,所以失败模式非常安静。

1 个答案:

答案 0 :(得分:4)

我在你的代码中添加了check_iterator函数。如果你用这个函数装饰你的协程,它将打印信息,如果你的协程是直接调用的,并且不能使用__iter__访问。根据您的实际代码,您可能需要进行更完整的实现并包装__next__。不过,这可能会稍微降低一点。

import asyncio
import functools

class IterWrap(object):
    def __init__(self, f, *args, **kwds):
        self.iterated = False
        self.info = [f, args, kwds]
        self.f = f(*args, **kwds)

    def __iter__(self):
        self.iterated = True
        return iter(self.f)

    def __del__(self):
        if not self.iterated:
            print("Did not yield: %s" % self.info)

def check_iterator(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        return IterWrap(f, *args, **kwds)
    return wrapper

@check_iterator
@asyncio.coroutine
def A(msg):
    print(msg)
    yield from asyncio.sleep(1)

@asyncio.coroutine
def B():
    while True :
        yield from A('1')
        A('2')
        yield from A('3')

loop = asyncio.get_event_loop()
loop.run_until_complete(B())

在Python 3.4上运行它的结果是:

1
Did not yield: [<function A at 0xb6e3189c>, ('2',), {}]
3
1
Did not yield: [<function A at 0xb6e3189c>, ('2',), {}]
3
1
Did not yield: [<function A at 0xb6e3189c>, ('2',), {}]
3
1
Did not yield: [<function A at 0xb6e3189c>, ('2',), {}]
3