[Python-Dev] async/await in Python; v2 (original) (raw)
Greg Ewing greg.ewing at canterbury.ac.nz
Thu Apr 23 04:58:37 CEST 2015
- Previous message (by thread): [Python-Dev] async/await in Python; v2
- Next message (by thread): [Python-Dev] async/await in Python; v2
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 04/23/2015 04:18 AM, Yury Selivanov wrote:
2. We'll hack Gen(/ceval.c?) objects to raise an error if they are called directly and have a 'COCOROUTINE' flag.
By "Gen", do you mean the generator-function or the generator-iterator?
That flag has to be on the generator-function, not the generator-iterator, otherwise by the time ceval sees it, the call that should have been forbidden has already been made.
To make this work without flagging the function, it would be necessary to check the result of every function call that wasn't immediately awaited and raise an exception if it were awaitable. But that would mean awaitable objects not being fully first-class citizens, since there would be some perfectly reasonable things that you can't do with them. I suspect it would make writing the kernel of a coroutine-scheduling system such as asyncio very awkward, perhaps impossible, to write in pure Python.
3. Task(), createtask() and async() will be modified to call 'coro.await(..)' if 'coro' has a 'COCOROUTINE' flag.
Or, as I pointed out earlier, the caller can wrap the argument in something equivalent to costart().
4. 'await' will require parentheses grammatically. That will make it different from 'yield' expression. For instance, I still don't know what would 'await coro(123)()' mean.
In PEP 3152, cocall binds to the nearest set of function-calling parens, so 'cocall f()()' is parsed as '(cocall f())()'. If you want it the other way, you have to write it as 'cocall (f())()'.
I know that's a somewhat arbitrary thing to remember, and it makes chained function calls a bit harder to write and read. But chaining calls like that is a fairly rare thing to do, in contrast with using a call expression as an argument to another call, which is very common.
That's not the only case, either. Just about any unparenthesised use of yield-from other than the sole contents of the RHS of an assignment seems to be disallowed. All of these are currently syntax errors, for example:
yield from f(x) + yield from g(x)
x + yield from g(x)
[yield from f(x)]
5. 'await foo(*a, **k)' will be an equivalent to 'yield from type(coro).await(coro, *a, **k)'
Again, I'm not sure whether you're proposing to make the functions the await-able objects rather than the iterators (which would effectively be PEP 3152 with cocall renamed to await) or something else. I won't comment further on this point until that's clearer.
6. If we ever decide to implement coroutine-generators -- async def functions with 'await' and some form of 'yield' -- we'll need to reverse the rule -- allow call and disallow await on such objects (so that you'll be able to write 'async for item in corogen()' instead of 'async for item in await corogen()'.
Maybe. I haven't thought that idea through properly yet. Possibly the answer is that you define such a function using an ordinary "def", to match the way it's called. The fact that it's an async generator is then indicated by the fact that it contains "async yield".
-- Greg
- Previous message (by thread): [Python-Dev] async/await in Python; v2
- Next message (by thread): [Python-Dev] async/await in Python; v2
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]