内置函数上的 Python 协程

标签 python tornado coroutine python-asyncio built-in

我目前正在使用 python 3.4、@coroutine 装饰器和 yield 关键字(在 Tornado 中)用于异步目的。 我编写了一个 ORM,其中包含许多对象自省(introspection),它调用“慢速”数据库并覆盖 __init____contains__ 等内置函数。 我的问题是: 例如,当我的异步代码在对象的 __contains__ 定义中时,当我在 tornado Controller 中使用“in”运算符时,如何隐式/透明地调用它? 隐含的,因为我不希望 Controller 端开发人员在调用内置函数时更改他的代码。

最佳答案

如果我正确理解这个问题,答案是你不能;没有办法将魔术方法编写为显式协程,并使其在被 Python 隐式调用时正常运行。这是 well-known limitation显式协程。

所以,如果你有这个:

class SomeObj:
    @coroutine
    def __contains__(self, obj):
        exists = yield self.somemethod(obj)
        return exists

这不会执行您希望它执行的操作:

o = SomeObj()
'x' in o # This won't work right

Python 不期望 __contains__ 是协程,如果是协程则不会正常运行 - 语言的核心对 tornado 一无所知,或 asyncio,或用于实现这些协程的任何其他框架,并且不会与它们正确集成。这同样适用于其他隐式调用的魔术方法,如 __init____getattr__ 等。

如果需要挂起,则必须使用 yieldyield from 显式调用方法(取决于框架)。通常,这意味着使用一个函数(或者可能是一个 @classmethod)来实例化您的 SomeObj,然后让该函数调用一个执行缓慢的异步调用的方法,而不是在 __init__ 中完成这一切:

@coroutine
def create_someobj():
   s = SomeObj()
   yield s.slow_init()
   return s

并且只需调用一个普通的协程方法,如 contains 而不是依赖于 in 关键字。不理想,但这就是我们生活的世界。

也就是说,正在努力改进这一点; PEP 492 ,除了为协程引入新语法外,还增加了对异步 for 循环和上下文管理器的支持(使用专门为异步设计的新魔术方法)。因此,从 Python 3.5 开始,您可以:

async def some_func():  # async is used instead of a coroutine decorator
    # Assume SomeObj implements __anext__, __aiter__, __aenter__, and __aexit__
    s = SomeObj()
    async for item in s:  # You can suspend while iterating over s using __anext__
       print(item)

    async with SomeObj() as s: # You can suspend on enter and exit of this context manager using __aenter__ and __aexit__
        await s.some_method() # await is used instead of yield from

关于内置函数上的 Python 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30447347/

相关文章:

python - 使用 QT 示例的 PyQt5.Qt3DCore 中的回调机制有什么问题

python - 在 python 3.7 中使用 exec() 导入别名不起作用

debugging - 在 Tornado 应用程序中设置断点

python - 使用适用于 Python SDK 的 Twisted API 进行异步 N1QL couchbase 查询

c++ - "yield"C++ 关键字,如何从我的函数返回迭代器?

Python按索引选择列表中的元素

python - 将 einsum 符号转换为 for 循环

django - Tornado 与 Django 身份验证

Python asyncio、futures 和 yield from

kotlin - Kotlin 挂起函数会阻塞吗?