[英]Python coroutines on builtin functions
I'm currently using python 3.4, @coroutine decorator and yield keyword (in tornado) for asynchronous purposes. 我目前正在使用python 3.4,@ coroutine decorator和yield关键字(在龙卷风中)用于异步目的。 I wrote an ORM with a lot of objects instrospection which call a "slow" database and override built-in functions like
__init__
or __contains__
. 我写了一个带有很多对象instros的ORM,它调用了一个“慢”数据库并覆盖内置函数,如
__init__
或__contains__
。 My question is : For example, when my asynchronous code is in the __contains__
definition of an object, how can I call it implicitly/transparently when I use the "in" operator in my tornado controller? 我的问题是:例如,当我的异步代码在对象的
__contains__
定义中时,当我在龙卷风控制器中使用“in”运算符时,如何隐式/透明地调用它? Implicit because I don't want the controller-side developper to change his code when he call built-in functions. 隐含,因为我不希望控制器端开发人员在调用内置函数时更改其代码。
If I understand the question properly, the answer is that you can't; 如果我理解这个问题,那么答案就是你做不到; there's no way to write a magic method as an explicit coroutine and have it behave properly when called implicitly by Python.
没有办法将魔术方法编写为显式协程,并且在Python隐式调用时使其行为正常。 This is a well-known limitation of explicit coroutines.
这是显式协同程序的众所周知的 限制 。
So, if you have this: 所以,如果你有这个:
class SomeObj:
@coroutine
def __contains__(self, obj):
exists = yield self.somemethod(obj)
return exists
This won't do what you want it to do: 这不会做你想做的事:
o = SomeObj()
'x' in o # This won't work right
Python doesn't expect __contains__
to be a coroutine, and won't behave properly if it is - the core of the language doesn't know anything about tornado
, or asyncio
, or any other frameworks used to implement these coroutines, and won't integrate with them properly. Python不希望
__contains__
成为一个协同程序,并且如果它不会正常运行 - 该语言的核心对tornado
, asyncio
或用于实现这些协同程序的任何其他框架都不了解,并赢得了'与他们妥善整合。 The same applies for other implicitly-called magic methods like __init__
, __getattr__
, etc. 这同样适用于其他隐式调用的魔术方法,如
__init__
, __getattr__
等。
If you need to suspend, you have to explicitly call a method using yield
or yield from
(depending on the framework). 如果需要挂起,则必须使用
yield
或yield from
显式调用方法(取决于框架)。 Generally, this means using a function (or perhaps a @classmethod
) to instantiate your SomeObj
and then having that function call a method that does the slow, asynchronous call, rather than doing it all in __init__
: 通常,这意味着使用函数(或者可能是
@classmethod
)来实例化SomeObj
,然后让该函数调用一个执行慢速异步调用的方法,而不是在__init__
所有操作:
@coroutine
def create_someobj():
s = SomeObj()
yield s.slow_init()
return s
And just calling a normal coroutine method called something like contains
instead of relying on the in
keyword. 只是调用一个普通的协程方法,称为
contains
而不是依赖于in
关键字。 Not ideal, but that's the world we live in. 不理想,但这就是我们生活的世界。
That said, there is some effort being made to improve this; 也就是说,正在努力改善这一点; PEP 492 , in addition to introducing a new syntax for coroutines, adds support for asynchronous for-loops and context managers (using new magic methods specifically designed to be asynchronous).
PEP 492除了引入协程的新语法外,还增加了对异步for循环和上下文管理器的支持(使用专门设计为异步的新魔术方法)。 So starting with Python 3.5, you can this:
所以从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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.