简体   繁体   English

关于内置函数的Python协程

[英]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__成为一个协同程序,并且如果它不会正常运行 - 该语言的核心对tornadoasyncio或用于实现这些协同程序的任何其他框架都不了解,并赢得了'与他们妥善整合。 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). 如果需要挂起,则必须使用yieldyield 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM