[Python Home] [PEP Index] [PEP Source] |
PEP: | XXX |
---|---|
Title: | Concatenation by multi-argument constructors. |
Version: | $Revision: 32 $ |
Last-Modified: | $Date: 2006-04-12 02:30:20 -0700 (Wed, 12 Apr 2006) $ |
Author: | Beni Cherniavsky <cben at users.sf.net> |
Status: | Draft |
Type: | Standards Track |
Content-Type: | text/x-rst |
Created: | 29-Nov-2003 |
Python-Version: | 2.4 |
Post-History: | 06-Aug-2001 |
Python's current ways to concatenate sequences are less convenient than they could be (the + operator requires the operands to have the same type). There is no obvious way to combine dictionaries in a single expression at all. "Concatenating" iterators is supported but is placed in the itertools module.
This PEP proposes a consistent set of extensions to the list(), tuple(), str() and dict() constructors to concatenate several values by giving them multiple arguments. iter() is similarly extended to behave as itertools.ichain(). All arguments are converted in the same ways as a single argument is now converted.
The list(), tuple(), str() and dict() constructors as well as the iter() function are to be extended to accept multiple arguments.
For the sequence constructors, the result is the concatenation of the values they would currently return for a single value.
The dict() constructor is also extended to accept multiple arguments. The result is defined as equivallent to doing:
d = {} for arg in args: d.update(dict(arg)) return d
where dict(arg) interprets each argument as it currently does for a single argument.
In other words, all resulting items are merged into a single dictionary, resolving each repeating key in favor of the last value given for it.
If dict() is called with both positional and keyword arguments, the keyword arguments are applied after all postional arguments.
iter() is extended to accept multiple arguments, behaving as itertools.ichain.
Suppose you want to create a list by concatenating several iterables. You can use the + operator only if they are all of the same type. When the types differ, there is no obvious type for the result, so + raises an exception (taking the type of the left operand would be a bad idea because it's desirable for + to be commutative, if not in values than at least in types). So you have to explicitly convert every object:
list(foo) + list(bar) + list(baz)
This looks redudant and is also sub-optimal because it creates 3 temporal list objects and takes O(N**2) time for N objects. This PEP stems from the simple observation that the notation:
list(foo, bar, baz)
would solve the above problems and has no assigned meaning. The current behaviors allowing to pass 0 or 1 argument would elegantly become special cases of the new behavior.
Whatever holds for lists should also hold for tuples and probably strings. For strings, it's important that each argument is processed exactly as str currently does for a single argument- it's not a simple concatenation of iterables. The new notation would be especailly convenient for strings, potentially replacing string formatting operations where all you need is to convert some values to strings and concatenate the results:
str("=== ", title, " ===")
It also makes sense to extend it to dictionaries. By "concatenating" dictionaries I mean the equivallent of:
d = d1.copy() d.update(d2) d.update(d3)
except that a single expression is desired. Surprisingly, there is currently no sane way to do it in Python! The closest candidate is:
dict(d1.items() + d2.items() + d3.items())
Again, it's useful to allow mixing of mapping and sequence-of-pairs arguments and even mixing of positional and keyword arguments. That would make creating a dictionary differing in a single value as easy as:
dict(d, foo=bar)
Last, the iter constructor also accepts iterables so it should also be extended in this way. This extension is already available as itertools.ichain and you can use it for effecient concatenation:
list(ichain(foo, bar)) dict(ichain(foo.items(), bar.items()))
but it would be more convenient to have it available as:
iter(foo, bar)
There is already a two-argument version of iter() but the first argument is a callable rather than an iterable so there is no conflict; perhaps even mixing iterables with callable/sentinel pairs should be allowed.
This document has been placed in the public domain.