Allow async defs for __await__

Hi, I suggest to allow defining awaitable classes in terms of `async def`-s: class FeynmanAlgorithm: async def __await__(self): await self.write_down_the_problem() await self.think_real_hard() await self.write_down_the_solution() IMO, this would be the "one obvious way" for anyone who's using it for anything other than defining low-level primitives. It is also easier to teach and and more consistent with how you can define iterables - where `__iter__` is explicitly allowed to be defined in terms of generator function (which I would consider the equivalent to the async defs of awaitables). The implementation could be as easy as calling `__await__` as long as the returned object is not an iterator instead of going straight to TypeError. Currently `__await__` must return an iterator, and one has to define a separate function or method (or use a decorator) to do the same, e.g.: class FeynmanAlgorithm: def __await__(self): return self.perform().__await__() async def perform(self): [...] IMO, this is far from obvious and has been subject to a few subtle differences between python versions. For example: import asyncio class Waiter: def __await__(self): return asyncio.sleep(1).__await__() asyncio.get_event_loop().run_until_complete( asyncio.ensure_future(Waiter())) works fine on python 3.7 but fails on python 3.5 with "AttributeError: 'generator' object has no attribute '__await__'" because some awaitables are implemented using generator type coroutines. Adding to potential confusion, `async def __await__` seems to be work in certain situations: import asyncio class Waiter: async def __await__(self): await asyncio.sleep(1) # this works on py3.7: asyncio.get_event_loop().run_until_complete( asyncio.ensure_future(Waiter())) but, awaiting them in a coroutine context causes an error: async def foo(): await Waiter() # "TypeError: __await__() returned a coroutine": asyncio.get_event_loop().run_until_complete( asyncio.ensure_future(foo())) In earlier python versions (at least up to 3.5) the situation is somewhat reversed. The `yield from` analogue of the above used to work in coroutine context: import asyncio class Waiter: def __iter__(self): yield from asyncio.sleep(1) @asyncio.coroutine def foo(): yield from Waiter() # works on py3.5: asyncio.get_event_loop().run_until_complete( asyncio.ensure_future(foo())) While the following doesn't: # "TypeError: An asyncio.Future, a coroutine or an awaitable is required": asyncio.get_event_loop().run_until_complete( asyncio.ensure_future(Waiter())) What do you think? Kind regards, Thomas See also: https://stackoverflow.com/questions/33409888/how-can-i-await-inside-future-l...
participants (1)
-
Thomas Gläßle