Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 448 – Additional Unpacking Generalizations

Author:
Joshua Landau <joshua at landau.ws>
Discussions-To:
Python-Ideas list
Status:
Final
Type:
Standards Track
Created:
29-Jun-2013
Python-Version:
3.5
Post-History:


Table of Contents

Abstract

This PEP proposes extended usages of the* iterable unpackingoperator and** dictionary unpacking operatorsto allow unpacking in more positions, an arbitrary number oftimes, and in function calls and displays.

Function calls are proposed to support an arbitrary number ofunpackings rather than just one:

>>>print(*[1],*[2],3)1 2 3>>>dict(**{'x':1},y=2,**{'z':3}){'x': 1, 'y': 2, 'z': 3}

Unpacking is proposed to be allowed inside tuple, list, set,and dictionary displays:

>>>*range(4),4(0, 1, 2, 3, 4)>>>[*range(4),4][0, 1, 2, 3, 4]>>>{*range(4),4}{0, 1, 2, 3, 4}>>>{'x':1,**{'y':2}}{'x': 1, 'y': 2}

In dictionaries, later values will always override earlier ones:

>>>{'x':1,**{'x':2}}{'x': 2}>>>{**{'x':2},'x':1}{'x': 1}

This PEP does not include unpacking operators inside list, set anddictionary comprehensions although this has not been ruled out forfuture proposals.

Rationale

Current usage of the* iterable unpacking operator featuresunnecessary restrictions that can harm readability.

Unpacking multiple times has an obvious rationale. When you want tounpack several iterables into a function definition or follow an unpackwith more positional arguments, the most natural way would be to write:

function(**kw_arguments,**more_arguments)function(*arguments,argument)

Simple examples where this is useful areprint andstr.format.Instead, you could be forced to write:

kwargs=dict(kw_arguments)kwargs.update(more_arguments)function(**kwargs)args=list(arguments)args.append(arg)function(*args)

or, if you know to do so:

fromcollectionsimportChainMapfunction(**ChainMap(more_arguments,arguments))fromitertoolsimportchainfunction(*chain(args,[arg]))

which add unnecessary line-noise and, with the first methods, causesduplication of work.

There are two primary rationales for unpacking inside of containers.Firstly there is a symmetry of assignment, wherefst,*other,lst=elems andelems=fst,*other,lst are approximate inverses,ignoring the specifics of types. This, in effect, simplifies thelanguage by removing special cases.

Secondly, it vastly simplifies types of “addition” such as combiningdictionaries, and does so in an unambiguous and well-defined way:

combination={**first_dictionary,"x":1,"y":2}

instead of:

combination=first_dictionary.copy()combination.update({"x":1,"y":2})

which is especially important in contexts where expressions arepreferred. This is also useful as a more readable way of summingiterables into a list, such asmy_list+list(my_tuple)+list(my_range) which is now equivalent to just[*my_list,*my_tuple,*my_range].

Specification

Function calls may accept an unbounded number of* and**unpackings. There will be no restriction of the order of positionalarguments with relation to* unpackings nor any restriction of theorder of keyword arguments with relation to** unpackings.

Function calls continue to have the restriction that keyword argumentsmust follow positional arguments and** unpackings must additionallyfollow* unpackings.

Currently, if an argument is given multiple times — such as apositional argument given both positionally and by keyword — aTypeError is raised. This remains true for duplicate argumentsprovided through multiple** unpackings,e.g.f(**{'x':2},**{'x':3}), except that the error will bedetected at runtime.

A function looks like this:

function(argumentor*args,argumentor*args,...,kwargumentor*args,kwargumentor*args,...,kwargumentor**kwargs,kwargumentor**kwargs,...)

Tuples, lists, sets and dictionaries will allow unpacking. This willact as if the elements from unpacked items were inserted in order atthe site of unpacking, much as happens in unpacking in a function-call.Dictionaries require** unpacking; all the others require* unpacking.

The keys in a dictionary remain in a right-to-left priority order, so{**{'a':1},'a':2,**{'a':3}} evaluates to{'a':3}. Thereis no restriction on the number or position of unpackings.

Disadvantages

The allowable orders for arguments in a function call are morecomplicated than before. The simplest explanation for the rulesmay be “positional arguments precede keyword arguments and**unpacking;* unpacking precedes** unpacking”.

Whilst*elements,=iterable causeselements to be a list,elements=*iterable, causeselements to be a tuple. Thereason for this may confuse people unfamiliar with the construct.

Concerns have been raised about the unexpected difference betweenduplicate keys in dictionaries being allowed but duplicate keysin function call syntax raising an error. Although this is alreadythe case with current syntax, this proposal might exacerbate theissue. It remains to be seen how much of an issue this is in practice.

Variations

The PEP originally considered whether the ordering of argument typesin a function call (positional, keyword,* or**) could becomeless strict. This met little support so the idea was shelved.

Earlier iterations of this PEP allowed unpacking operators insidelist, set, and dictionary comprehensions as a flattening operatorover iterables of containers:

>>>ranges=[range(i)foriinrange(5)]>>>[*itemforiteminranges][0, 0, 1, 0, 1, 2, 0, 1, 2, 3]>>>{*itemforiteminranges}{0, 1, 2, 3}

This was met with a mix of strong concerns about readability and mildsupport. In order not to disadvantage the less controversial aspectsof the PEP, this was not accepted with the rest of the proposal.

Unbracketed comprehensions in function calls, such asf(xforxinit),are already valid. These could be extended to:

f(*xforxinit)==f((*xforxinit))f(**xforxinit)==f({**xforxinit})

However, it wasn’t clear if this was the best behaviour or if it shouldunpack into the arguments of the call tof. Since this is likely to beconfusing and is of only very marginal utility, it is not included in thisPEP. Instead, these will throw aSyntaxError and comprehensions withexplicit 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[2].This currently includes support for unpacking inside comprehensions, whichshould be removed.

References

[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(https://github.com/python/cpython/issues/46545)

[3] Discussion on Python-ideas list, “list / array comprehensions extension”, Alexander Heger (https://mail.python.org/pipermail/python-ideas/2011-December/013097.html)

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0448.rst

Last modified:2025-02-01 08:55:40 GMT


[8]ページ先頭

©2009-2025 Movatter.jp