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

John Pinner funthyme at gmail.com
Thu Aug 18 11:26:35 CEST 2011


On Aug 3, 2:45 am, gc <gc1... at gmail.com> wrote:
> 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!

I hesitate to put this forward, as it smells and is probably
considered bad practice, but heh!

for char in 'abcdefg' :
    globals()[ char ] = dict()

does what you wanted.

Best wishes,

John
--





More information about the Python-list mailing list