Syntactic sugar for assignment statements: one value to multiple targets?

gc gc1223 at gmail.com
Tue Aug 2 21:45:15 EDT 2011


Hi everyone! Longtime lurker, hardly an expert, but I've been using
Python for various projects since 2007 and love it.

I'm looking for either (A) suggestions on how to do a very common
operation elegantly and Pythonically, or (B) input on whether my
proposal is PEP-able, assuming there's no answer to A. (The proposal
is sort of like the inverse of PEP 3132; I don't think it has been
proposed before, sorry if I missed it.)

Anyway, I frequently need to initialize several variables to the same
value, as I'm sure many do. Sometimes the value is a constant, often
zero; sometimes it's more particular, such as defaultdict(list). I use
dict() below.

Target lists using comma separation are great, but they don't work
very well for this task. What I want is something like

a,b,c,d,e = *dict()

where * in this context means something like "assign separately to
all." I'm not sure that * would the best sugar for this, but the
normal meaning of * doesn't seem as if it would ever be valid in this
case, and it somehow feels right (to me, anyway).

Statements fitting the form above would get expanded during parsing to
a sequence of separate assignments (a = dict(); b = dict(); c = dict()
and so forth.) That's all there is to it. Compared to the patterns
below, it's svelte, less copy-paste-y (so it removes an opportunity
for inconsistency, where I remember to change a-d to defaultdict(list)
but forget with e), and it doesn't require me to keep count of the
number of variables I'm initializing.

This would update section 6.2 of the language reference and require a
small grammar expansion.

But: Is there already a good way to do this that I just don't know?
Below, I compare four obvious patterns, three of which are correct but
annoying and one of which is incorrect in a way which used to surprise
me when I was starting out.

# Option 1 (separate lines)
# Verbose and annoying, particularly when the varnames are long and of
irregular length

a = dict()
b = dict()
c = dict()
d = dict()
e = dict()

# Option 2 (one line)
# More concise but still pretty annoying, and hard to read (alternates
variables and assignments)

a = dict(); b = dict(); c = dict(); d = dict(); e = dict()

# Option 3 (multiple target list: this seems the most Pythonic, and is
normally what I use)
# Concise, separates variables from assignments, but somewhat
annoying; have to change individually and track numbers on both sides.

a,b,c,d,e = dict(),dict(),dict(),dict(),dict()

# Option 4 (iterable multiplication)
# Looks better, and if the dict() should be something else, you only
have to change it once, but the extra brackets are ugly and you still
have to keep count of the targets...

a,b,c,d,e = [dict()] * 5

# and it will bite you...

>>> a[1] = 1
>>> b
{1: 1}
>>> id(a) == id(b)
True

# Gotcha!

# Other forms of 4 also have this behavior:

a,b,c,d,e = ({},) * 5
>>> a[1] = 1
>>> b
{1: 1}

Alternatively, is there a version of iterable multiplication that
creates new objects rather than just copying the reference? That would
solve part of the problem, though it would still look clunky and you'd
still have to keep count.

Any thoughts? Thanks!



More information about the Python-list mailing list