[Python-Dev] Generalizing *args and **kwargs

Thomas Wouters thomas at xs4all.net
Wed Feb 15 11:37:46 CET 2006

I've been thinking about generalization of the *args/**kwargs syntax for
quite a while, and even though I'm pretty sure Guido (and many people) will
consider it overgeneralization, I am finally going to suggest it. This whole
idea is not something dear to my heart, although I obviously would like to
see it happen. If the general vote is 'no', I'll write a small PEP or add it
to PEP 13 and be done with it.

The grand total of the generalization would be something like this:

Allow 'unpacking' of arbitrary iterables in sequences:
>>> iterable = (1, 2)
>>> ['a', 'b', *iterable, 'c']
['a', 'b', 1, 2, 'c']
>>> ('a', 'b', *iterable, 'c')
('a', 'b', 1, 2, 'c')

Possibly also allow 'unpacking' in list comprehensions and genexps:
>>> [ *subseq for subseq in [(1, 2), (3, 4)] ]
[1, 2, 3, 4]

(You can already do this by adding an extra 'for' loop inside the LC)

Allow 'unpacking' of mapping types (anything supporting 'items' or
'iteritems') in dictionaries:
>>> args = {'verbose': 1}
>>> defaults = {'verbose': 0}
>>> {**defaults, **args, 'fixedopt': 1}
{'verbose': 1, 'fixedopt': 1}

Allow 'packing' in assignment, stuffing left-over items in a list.
>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(2)
(0, 1, [])

(A list because you can't always take the type of the RHS and it's the right
Python type for 'an arbitrary length homogeneous sequence'.)

While generalizing that, it may also make sense to allow:

>>> def spam(*args, **kwargs):
...     return args, kwargs
>>> args = (1, 2); kwargs = {'eggs': 'no'}
>>> spam(*args, 3)
((1, 2, 3), {})
>>> spam(*args, 3, **kwargs, spam='extra', eggs='yes')
((1, 2, 3), {'spam': 'extra', 'eggs': 'yes'})

(In spite of the fact that both are already possible by fiddling args/kwargs
beforehand or doing '*(args + (3,))'.)

Maybe it also makes sense on the defining side, particularly for keyword
arguments to indicate 'keyword-only arguments'. Maybe with a '**' without a
name attached:

>>> def spam(pos1, pos2, **, kwarg1=.., kwarg2=..)

But I dunno yet.

Although I've made it look like I have a working implementation, I haven't.
I know exactly how to do it, though, except for the AST part ;) Once I
figure out how to properly work with the AST code I'll probably write this
patch whether it's a definite 'no' or not, just to see if I can. I wouldn't
mind if people gave their opinion, though.

Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!

More information about the Python-Dev mailing list