Update to PEP 448 -- approved 2 out of 3, rejected *comprehension.
This commit is contained in:
parent
f2db585e09
commit
401c977971
115
pep-0448.txt
115
pep-0448.txt
|
@ -4,11 +4,11 @@ Version: $Revision$
|
|||
Last-Modified: $Date$
|
||||
Author: Joshua Landau <joshua@landau.ws>
|
||||
Discussions-To: python-ideas@python.org
|
||||
Status: Draft
|
||||
Status: Accepted
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 29-Jun-2013
|
||||
Python-Version: 3.4
|
||||
Python-Version: 3.5
|
||||
Post-History:
|
||||
|
||||
|
||||
|
@ -50,15 +50,9 @@ In dictionaries, later values will always override earlier ones::
|
|||
>>> {**{'x': 2}, 'x': 1}
|
||||
{'x': 1}
|
||||
|
||||
Unpacking is proposed to be allowed inside list, set,
|
||||
and dictionary comprehensions::
|
||||
|
||||
>>> ranges = [range(i) for i in range(5)]
|
||||
>>> [*item for item in ranges]
|
||||
[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]
|
||||
|
||||
>>> {*item for item in ranges}
|
||||
{0, 1, 2, 3}
|
||||
This PEP does not include unpacking operators inside list, set and
|
||||
dictionary comprehensions although this has not been ruled out for
|
||||
future proposals.
|
||||
|
||||
|
||||
Rationale
|
||||
|
@ -121,14 +115,6 @@ list(my_range)`` which is now equivalent to just ``[*my_list,
|
|||
*my_tuple, *my_range]``.
|
||||
|
||||
|
||||
The addition of unpacking to comprehensions is a logical extension.
|
||||
It's usage will primarily be a neat replacement for ``[i for j in
|
||||
list_of_lists for i in j]``, as the more readable
|
||||
``[*l for l in list_of_lists]``. The iterable version,
|
||||
``(*l for l in list_of_lists)``, replaces ``itertools.chain.from_iterable``.
|
||||
Other uses are possible, but expected to occur rarely.
|
||||
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
|
@ -145,7 +131,8 @@ Currently, if an argument is given multiple times — such as a
|
|||
positional argument given both positionally and by keyword — a
|
||||
``TypeError`` is raised. This remains true for duplicate arguments
|
||||
provided through multiple ``**`` unpackings,
|
||||
e.g. ``f(**{'x': 2}, **{'x': 3})``.
|
||||
e.g. ``f(**{'x': 2}, **{'x': 3})``, except that the error will be
|
||||
detected at runtime.
|
||||
|
||||
A function looks like this::
|
||||
|
||||
|
@ -159,40 +146,17 @@ Tuples, lists, sets and dictionaries will allow unpacking. This will
|
|||
act as if the elements from unpacked items were inserted in order at
|
||||
the site of unpacking, much as happens in unpacking in a function-call.
|
||||
Dictionaries require ``**`` unpacking; all the others require ``*`` unpacking.
|
||||
A dictionary's key remain in a right-to-left priority order, so
|
||||
|
||||
The keys in a dictionary remain in a right-to-left priority order, so
|
||||
``{**{'a': 1}, 'a': 2, **{'a': 3}}`` evaluates to ``{'a': 3}``. There
|
||||
is no restriction on the number or position of unpackings.
|
||||
|
||||
Comprehensions, by simple extension, will support unpacking. As before,
|
||||
dictionaries require ``**`` unpacking, all the others require ``*``
|
||||
unpacking and key priorities are unchanged.
|
||||
|
||||
For example::
|
||||
|
||||
{*[1, 2, 3], 4, 5, *{6, 7, 8}}
|
||||
|
||||
(*e for e in [[1], [3, 4, 5], [2]])
|
||||
|
||||
{**dictionary for dictionary in (globals(), locals())}
|
||||
|
||||
{**locals(), "override": None}
|
||||
|
||||
Unbracketed comprehensions in function calls, such as ``f(x for x in it)``,
|
||||
are already valid. These could be extended to::
|
||||
|
||||
f(*x for x in it) == f((*x for x in it))
|
||||
f(**x for x in it) == f({**x for x in it})
|
||||
|
||||
However, this is likely to be confusing and is not included in this
|
||||
PEP. These will throw ``SyntaxError`` and comprehensions with explicit
|
||||
brackets should be used instead.
|
||||
|
||||
|
||||
Disadvantages
|
||||
=============
|
||||
|
||||
The allowable orders for arguments in a function call are more
|
||||
complicated than before. The simplest explanation for the rules
|
||||
complicated than before. The simplest explanation for the rules
|
||||
may be "positional arguments precede keyword arguments and ``**``
|
||||
unpacking; ``*`` unpacking precedes ``**`` unpacking".
|
||||
|
||||
|
@ -200,24 +164,75 @@ Whilst ``*elements, = iterable`` causes ``elements`` to be a list,
|
|||
``elements = *iterable,`` causes ``elements`` to be a tuple. The
|
||||
reason for this may confuse people unfamiliar with the construct.
|
||||
|
||||
Concerns have been raised about the unexpected difference between
|
||||
duplicate keys in dictionaries being allowed but duplicate keys
|
||||
in function call syntax raising an error. Although this is already
|
||||
the case with current syntax, this proposal might exacerbate the
|
||||
issue. It remains to be seen how much of an issue this is in practice.
|
||||
|
||||
|
||||
Variations
|
||||
==========
|
||||
|
||||
The PEP originally considered whether the ordering of argument types
|
||||
in a function call (positional, keyword, ``*`` or ``**``) could become
|
||||
less strict. This met little support so the idea was shelved.
|
||||
|
||||
Earlier iterations of this PEP allowed unpacking operators inside
|
||||
list, set, and dictionary comprehensions as a flattening operator
|
||||
over iterables of containers::
|
||||
|
||||
>>> ranges = [range(i) for i in range(5)]
|
||||
>>> [*item for item in ranges]
|
||||
[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]
|
||||
|
||||
>>> {*item for item in ranges}
|
||||
{0, 1, 2, 3}
|
||||
|
||||
This was met with a mix of strong concerns about readability and mild
|
||||
support. In order not to disadvantage the less controversial aspects
|
||||
of the PEP, this was not accepted with the rest of the proposal.
|
||||
|
||||
Unbracketed comprehensions in function calls, such as ``f(x for x in it)``,
|
||||
are already valid. These could be extended to::
|
||||
|
||||
f(*x for x in it) == f((*x for x in it))
|
||||
f(**x for x in it) == f({**x for x in it})
|
||||
|
||||
However, it wasn't clear if this was the best behaviour or if it should
|
||||
unpack into the arguments of the call to `f`. Since this is likely to be
|
||||
confusing and is of only very marginal utility, it is not included in this
|
||||
PEP. Instead, these will throw a ``SyntaxError`` and comprehensions with
|
||||
explicit brackets should be used instead.
|
||||
|
||||
|
||||
Approval
|
||||
========
|
||||
|
||||
This PEP was accepted by Guido on February 25, 2015 [1]_.
|
||||
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
An implementation for Python 3.5 is found at Issue 2292 on bug tracker [1]_.
|
||||
An implementation for Python 3.5 is found at Issue 2292 on bug tracker [2]_.
|
||||
This currently includes support for unpacking inside comprehensions, which
|
||||
should be removed.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters
|
||||
.. [1] PEP accepted, "PEP 448 review", Guido van Rossum
|
||||
(https://mail.python.org/pipermail/python-dev/2015-February/138564.html)
|
||||
|
||||
.. [2] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters
|
||||
(http://bugs.python.org/issue2292)
|
||||
|
||||
.. [2] Discussion on Python-ideas list,
|
||||
.. [3] Discussion on Python-ideas list,
|
||||
"list / array comprehensions extension", Alexander Heger
|
||||
(http://mail.python.org/pipermail/python-ideas/2011-December/013097.html)
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
|
|
Loading…
Reference in New Issue