2015-05-25 71 views
4

我目前正在使用python 3.4,@coroutine裝飾器和yield關鍵字(在龍捲風)進行異步目的。 我寫了一個ORM,其中有很多對象的自相矛盾,它們調用一個「慢」數據庫並覆蓋內置函數,如__init____contains__。我的問題是: 例如,當我的異步代碼位於對象的__contains__定義中時,如何在我的龍捲風控制器中使用「in」運算符時隱式/透明地調用它? 隱含,因爲我不希望控制器端開發人員在調用內置函數時更改其代碼。關於內建函數的Python協程

+0

你能告訴我們一些代碼示例來演示你在問什麼嗎?這個問題有點不清楚。 –

回答

7

如果我正確理解這個問題,答案是你不能;沒有辦法將一種神奇的方法編寫成一個顯式的協程,並且在Python隱式調用時可以正常運行。這是顯式協程的一個well-knownlimitation

所以,如果你有這樣的:

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__是一個協程,並榮獲如果它的行爲正確 - 語言的核心並不知道tornadoasyncio或任何其他用於實現這些協同程序的框架,並且不會與其正確集成。這同樣適用於其他隱式堪稱神奇的方法,如__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