peps: pep-0492: v3; tp_await, noiter, new await syntax, etc
https://hg.python.org/peps/rev/4f50594e091e changeset: 5801:4f50594e091e user: Yury Selivanov <yselivanov@sprymix.com> date: Mon Apr 27 22:40:36 2015 -0400 summary: pep-0492: v3; tp_await, noiter, new await syntax, etc files: pep-0492.txt | 130 ++++++++++++++++++++++++++++++-------- 1 files changed, 101 insertions(+), 29 deletions(-) diff --git a/pep-0492.txt b/pep-0492.txt --- a/pep-0492.txt +++ b/pep-0492.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 09-Apr-2015 Python-Version: 3.5 -Post-History: 17-Apr-2015, 21-Apr-2015 +Post-History: 17-Apr-2015, 21-Apr-2015, 27-Apr-2015 Abstract @@ -155,12 +155,40 @@ It is a ``TypeError`` if ``__await__`` returns anything but an iterator. +* Objects defined with CPython C API with a ``tp_await`` function, + returning an iterator (similar to ``__await__`` method). + It is a ``SyntaxError`` to use ``await`` outside of a coroutine. It is a ``TypeError`` to pass anything other than an *awaitable* object to an ``await`` expression. +Syntax of "await" expression +'''''''''''''''''''''''''''' + +``await`` keyword is defined differently from ``yield`` and ``yield +from``. The main difference is that *await expressions* do not require +parentheses around them most of the times. + +Examples:: + +================================== ================================== +Expression Will be parsed as +================================== ================================== +``if await fut: pass`` ``if (await fut): pass`` +``if await fut + 1: pass`` ``if (await fut) + 1: pass`` +``pair = await fut, 'spam'`` ``pair = (await fut), 'spam'`` +``with await fut, open(): pass`` ``with (await fut), open(): pass`` +``await foo()['spam'].baz()()`` ``await ( foo()['spam'].baz()() )`` +``return await coro()`` ``return ( await coro() )`` +``res = await coro() ** 2`` ``res = (await coro()) ** 2`` +``func(a1=await coro(), a2=0)`` ``func(a1=(await coro()), a2=0)`` +================================== ================================== + +See `Grammar Updates`_ section for details. + + Asynchronous Context Managers and "async with" ---------------------------------------------- @@ -487,6 +515,49 @@ unsets the wrapper. +inspect.iscoroutine() and inspect.iscoroutineobject() +----------------------------------------------------- + +Two new functions are added to the ``inspect`` module: + +* ``inspect.iscoroutine(obj)`` returns ``True`` if ``obj`` is a + coroutine object. + +* ``inspect.iscoroutinefunction(obj)`` returns ``True`` is ``obj`` is a + coroutine function. + + +Differences between coroutines and generators +--------------------------------------------- + +A great effort has been made to make sure that coroutines and +generators are separate concepts: + +1. Coroutine objects do not implement ``__iter__`` and ``__next__`` + methods. Therefore they cannot be iterated over or passed to + ``iter()``, ``list()``, ``tuple()`` and other built-ins. They + also cannot be used in a ``for..in`` loop. + +2. ``yield from`` does not accept coroutine objects (unless it is used + in a generator-based coroutine decorated with ``types.coroutine``.) + +3. ``yield from`` does not accept coroutine objects from plain Python + generators (*not* generator-based coroutines.) + +4. ``inspect.isgenerator()`` and ``inspect.isgeneratorfunction()`` + return ``False`` for coroutine objects and coroutine functions. + + +Coroutine objects +----------------- + +Coroutines are based on generators internally, thus they share the +implementation. Similarly to generator objects, coroutine objects have +``throw``, ``send`` and ``close`` methods. ``StopIteration`` and +``GeneratorExit`` play the same role for coroutine objects (although +PEP 479 is enabled by default for coroutines). + + Glossary ======== @@ -500,11 +571,12 @@ details. :Future-like object: - An object with an ``__await__`` method returning an iterator. Can - be consumed by an ``await`` expression in a coroutine. A coroutine - waiting for a Future-like object is suspended until the Future-like - object's ``__await__`` completes, and returns the result. See - `Await Expression`_ for details. + An object with an ``__await__`` method, or a C object with + ``tp_await`` function, returning an iterator. Can be consumed by + an ``await`` expression in a coroutine. A coroutine waiting for a + Future-like object is suspended until the Future-like object's + ``__await__`` completes, and returns the result. See `Await + Expression`_ for details. :Awaitable: A *Future-like* object or a *coroutine object*. See `Await @@ -602,29 +674,16 @@ Grammar changes are also fairly minimal:: - await_expr: AWAIT test - await_stmt: await_expr - decorated: decorators (classdef | funcdef | async_funcdef) async_funcdef: ASYNC funcdef + compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | with_stmt + | funcdef | classdef | decorated | async_stmt) + async_stmt: ASYNC (funcdef | with_stmt | for_stmt) - compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | - with_stmt | funcdef | classdef | decorated | - async_stmt) - - flow_stmt: (break_stmt | continue_stmt | return_stmt | - raise_stmt | yield_stmt | await_stmt) - - atom: ('(' [yield_expr|await_expr|testlist_comp] ')' | - '[' [testlist_comp] ']' | - '{' [dictorsetmaker] '}' | - NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False’) - - expr_stmt: testlist_star_expr - (augassign (yield_expr|await_expr|testlist) | - ('=' (yield_expr|await_expr|testlist_star_expr))*) + power: atom_expr ['**' factor] + atom_expr: [AWAIT] atom trailer* Transition Period Shortcomings @@ -889,6 +948,15 @@ with the existing grammar. +Why "async for/with" instead of "await for/with" +------------------------------------------------ + +``async`` is an adjective, and hence it is a better choice for a +*statement qualifier* keyword. ``await for/with`` would imply that +something is awaiting for a completion of a ``for`` or ``with`` +statement. + + Why "async def" and not "def async" ----------------------------------- @@ -946,11 +1014,13 @@ * it would not be possible to create an object that works in both ``with`` and ``async with`` statements; -* it would look confusing and would require some implicit magic behind - the scenes in the interpreter; +* it would break backwards compatibility, as nothing prohibits from + returning a Future-like objects from ``__enter__`` and/or + ``__exit__`` in Python <= 3.4; * one of the main points of this proposal is to make coroutines as - simple and foolproof as possible. + simple and foolproof as possible, hence the clear separation of the + protocols. Why not reuse existing "for" and "with" statements @@ -1074,7 +1144,8 @@ 1. New syntax for defining coroutines: ``async def`` and new ``await`` keyword. -2. New ``__await__`` method for Future-like objects. +2. New ``__await__`` method for Future-like objects, and new + ``tp_await`` slot in ``PyTypeObject``. 3. New syntax for asynchronous context managers: ``async with``. And associated protocol with ``__aenter__`` and ``__aexit__`` methods. @@ -1087,7 +1158,8 @@ ``Await``. 6. New functions: ``sys.set_coroutine_wrapper(callback)``, - ``sys.get_coroutine_wrapper()``, and ``types.coroutine(gen)``. + ``sys.get_coroutine_wrapper()``, ``types.coroutine(gen)``, + ``inspect.iscoroutinefunction()``, and ``inspect.iscoroutine()``. 7. New ``CO_COROUTINE`` bit flag for code objects. -- Repository URL: https://hg.python.org/peps
participants (1)
-
yury.selivanov