[Python-checkins] peps: pep-0492: v3; tp_await, noiter, new await syntax, etc
yury.selivanov
python-checkins at python.org
Tue Apr 28 04:40:41 CEST 2015
https://hg.python.org/peps/rev/4f50594e091e
changeset: 5801:4f50594e091e
user: Yury Selivanov <yselivanov at 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
More information about the Python-checkins
mailing list