[Python-ideas] Inline assignments using "given" clauses
mistersheik at gmail.com
Sat May 12 20:06:02 EDT 2018
On Sat, May 12, 2018 at 2:28 PM Steven D'Aprano <steve at pearwood.info> wrote:
> Part 2.
> On Sat, May 12, 2018 at 08:16:07AM -0700, Neil Girdhar wrote:
> > I love given compared with := mainly because
> > * Python has a reputation for being working pseudocode, and given reads
> > like pseudocode. := needs to be deciphered by comparison especially in
> > complicated cases where multiple := operators are used on one line.
> Until you learn and become familiar with a new syntax, there is
> generally going to be a period you have to decipher it. I spent a long
> time mentally translating list comprehensions into mathematical set
> builder notation before it became second nature to me.
> Even now, I know people who find decorators and comprehensions
> indecipherable. Or at least, so they claim, and they aren't motivated to
> bother learning them. Oh well, that's their loss.
> Binding-expressions aren't like asynchronous programming, where the
> entire coding paradigm is different, and you literally have to think
> about your algorithms in another way. Whether you spell the binding
> target := expr
> expr as target
> expr -> target
> target given target = expr
> let target = expr
> : target expr ;
> (that last one is stolen from Forth, and should not be taken as a
> serious suggestion)
> is just a matter of spelling. We'll get used to whatever spelling it is.
> Some may be more convenient than others, or more error-prone, or may be
> harder to parse, but they're secondary issues. (Important, but still
> secondary.) Fundamentally, the operation is the same regardless of the
> - evaluate an expression
> - bind that value to a name
> - return the value
> (Except of course Nick's "given" suggestion is more complex, since the
> returned value is not necessarily the same as the bound value.)
> > * there are no difficult mental questions about evaluation order, e.g.,
> > a bracketed expression having multiple assignments.
> Aren't there just?
> x = 1
> print( x + x given x = 50 )
> Will that print 100, or 51? Brackets ought to make it clearer:
> (x + x given x = 50) # this ought to return 100
> x + (x given x = 50) # this ought to return 51
> but if I leave the brackets out, I have no idea what I'll get.
It has to be 100, or else outer parentheses change how an expression is
> > Similarly, instead of
> > (a.b(a) given a = c.d()) do I write (a.b(a := c.d())) or ((a :=
> > c.d()).b(a)) ?
> I would expect that your first example is a NameError:
> a.b(a := c.d())
> since Python evaluates arguments to a method *after* looking up the
> method. So that corresponds to:
> - look up "a" # NameError, unless you've already got an "a"
> - look up "a.b"
> - evaluate c.d()
> - assign that value to a
> - pass that to the a.b method we found earlier
> What you probably want is the second version:
> (a := c.d()).b(a)
> which of course looks like utter crap. It might look better if we use at
> least half-way sensible variable names and a more realistic looking
> example, instead of obfuscated one-letter names.
> (widget := widget_builder.new(*args)).method(widget)
> > * it avoids the question of what happens when := is used in a switch:
> > if (b := c) else d) Sometimes you want the assignment to happen
> > unconditionally (a if (b:=c) else d) + b; sometimes you don't. How do
> > force one case or the other?
> I think that this argument is really weak. The obvious answer is, if you
> don't want the assignment to happen unconditionally, then don't do the
> assignment unconditionally. Where you do it depends on when you want the
> assignment to take place. There's no mystery here.
> # unconditionally pop from a list
> (spam if mylist.pop(idx) else eggs) + mylist
> # conditionally pop from a list
> (mylist.pop(idx) if condition else eggs) + mylist
> (spam if condition else mylist.pop(idx)) + mylist
> Take your choice of which you want:
> (spam if (mylist := expr) else eggs) + mylist
> ((mylist := expr) if condition else eggs) + mylist
> (spam if condition else (mylist := expr)) + mylist
> Of course, in the last two cases, you're going to get a NameError when
> you try to add mylist if the ternary operator took the wrong branch.
> Unless you already defined mylist earlier.
That's the problem I'm showing. This is impossible:
(spam if (mylist := expr) else eggs) + mylist
but just fine with given:
else eggs) + mylist)
given mylist = expr)
> If you want something else, you have to explain what you want.
> > given makes it obvious by separating
> > assignment from the usage of its assignment target.
> This is just a purely mechanical source transformation from one to the
> other. Just replace ":" with "mylist given mylist " and you are done.
First of all, you cannot convert all := expressions to given expressions.
Even if you could, the point is that they are separated. I went over the
separation of concerns in my other mail.
> # unconditional version
> (spam if (mylist given mylist = expr) else eggs) + mylist
> # conditional versions
> ((mylist given mylist = expr) if condition else eggs) + mylist
> (spam if condition else (mylist given mylist = expr)) + mylist
> If you can write the "given" versions, then just do the reverse
> transformation and replace the redundant verbosity with a colon.
You can't always do that. I've given you two examples now where you cannot
> > Style:
> > * it avoids the big style question of when to use and when not to use
> > (Even if you ask people not to, people are going to write the
> > expression-statement a := b as a synonym for the statement a = b.)
> What if they do? Is it really the end of the world if some ex-Pascal
> coders or people with an over-developed desire for (foolish) consistency
> add a colon to their statement level assignments?
> Some people add semi-colons to their statements too. Do we care? No.
> But if it aggitates people so much, then I'm perfectly happy with
> Guido's suggestion that we simply ban top level binding expressions and
> require them to leave the colons out.
> > * it looks a lot like the existing Python "for" and "if" clauses, which
> > also do in-expression assignments.
> "if" clauses do an assignment? Have you borrowed the keys to Guido's
> time machine, and are writing from 2025 and Python 4.2? *wink*
> I don't think "given" expressions look even remotely similar to either.
> for target in iterable:
> if condition:
> another_expr given target = expr
I meant the clauses not the statements:
for x in it
given z = x.z)
All three clauses have the same format, and obvious temporal ordering. for
and given both bind a name that is visible to the expression and to clauses
> Aside from "all three use a keyword".
> Python-ideas mailing list
> Python-ideas at python.org
> Code of Conduct: http://python.org/psf/codeofconduct/
> You received this message because you are subscribed to a topic in the
> Google Groups "python-ideas" group.
> To unsubscribe from this topic, visit
> To unsubscribe from this group and all its topics, send an email to
> python-ideas+unsubscribe at googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Python-ideas