Use await with object that implements the __await__method

Asked

Viewed 78 times

1

From the Python 3.5 was introduced async/await I am implementing some objects long-awaited but I am met with doubts follows an example:

#!usr/bin/python3                                                                         
# -*- coding: utf-8 -*-                                                                   

import asyncio                                                                            


class Waiting:                                                                      

    def __await__(self):                                                                  
        print('__await__')                                                                
        yield from asyncio.sleep(3)                                                       
        print('Ok')                                                                       


async def main():                                                                         
    await Waiting()                                                                       


if __name__ == '__main__':                                                                
    loop = asyncio.get_event_loop()                                                       
    try:                                                                                  
        loop.run_until_complete(main())                                                   
    finally:                                                                              
        loop.close() 

If the script is executed the result will be:

__await__
Ok

Sure the script worked but if you try to implement it using the new reserved words of Python 3.5 I come across an error, follow the script:

#!usr/bin/python3                                                                         
# -*- coding: utf-8 -*-  



import asyncio                                                                            

class Waiting:                                                                      

    async def __await__(self):                                                            
        print('__await__')                                                                
        await asyncio.sleep(3)                                                            
        print('Ok')

async def main():                                                                         
    await Waiting() 




if __name__ == '__main__':                                                                
    loop = asyncio.get_event_loop()                                                       
    try:                                                                                  
        loop.run_until_complete(main())                                                   
    finally:                                                                              
        loop.close() 

I turned __await__ a co-routine and altered yield from for await and now when running the script I get:

Traceback (most recent call last):
  File "dunder_await.py", line 22, in <module>
    loop.run_until_complete(main())
  File "/usr/lib/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "dunder_await.py", line 16, in main
    await Waiting()
TypeError: __await__() returned a coroutine

Correct me if I’m wrong but for me to use await I have to define a co-routine and await should work as yield from or am I wrong? And why am I getting this error?

  • I think it would be interesting for you to hide the number of the lines in VIM before copying the code, as this makes it difficult to test your code since we would have to remove the numbers manually.

  • PEP 492 says that __await__ should return an iterator, but when you use the await it will return a co-routine.

  • I removed the lines I’m sorry for that.

1 answer

3


the magic function __await__ is for you to create an object "suitable" in the same way as the new reserved word async def... That is, if you use __await__ you don’t need to use async def:

class AsyncFunction:
    def __await__(self):
        ...
x = AsyncFunction()
await x

is the same as:

async def AsyncFunction():
    ...
x = AsyncFunction()
await x

So in your example you need to choose. Or define a function with async def or creates a class with __await__, both serve for the same thing but should not be used together.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.