[Python-ideas] Combining test and assignment
steve at pearwood.info
Sun Jan 22 05:51:13 CET 2012
Nick Coghlan wrote:
> This suggestion (i.e. embedded assignment in while and if headers) has
> been made several times, and always come to a grinding halt on one
> simple problem: it isn't expressive enough.
> The obvious escalation of the suggestion is to adopt "(EXPR as NAME)"
> as a general purpose embedded assignment expression. However, this
> idea has problems of its own:
I dislike assignment as an expression, and am glad that Python doesn't have
it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on
adding it to Python.
I believe it is an unnatural way of writing that obscures the code rather than
simplifies it. (Sometimes, shorter is not better.) For example, when writing
code, I might start off by thinking:
if spam() != 'ham':
Then I would apply DRY and factor out the call to spam:
x = spam()
if x != 'ham':
This matches my thought processes and corresponds to how you might naturally
describe the algorithm in English:
Let x equal spam().
If x != 'ham', then frobulate(x).
The important thing is that you name the thing you care about before using it.
I think this is a very natural way of writing: first you give the thing you
care about a name, then you refer to it by name.
Assignment as an expression feels unnatural to me:
if spam() as x != 'ham':
doesn't really correspond to any natural English order. The assignment is
dropped in the middle of another clause:
If -- let x = spam() -- x != 'ham', then frobulate(x).
It saves a line, but is not a natural way of writing for me. I would not like
to read code written that way.
Assignment as an expression also lends itself to writing buggy code like this:
while spam() as x and ham() as y:
which is wrong, because y won't be defined if x has a true value. The
alternative would require defeating the short-circuit nature of "and", which
would be bad.
Perhaps the only thing going for it is that it would allow list comprehensions
to not repeat themselves:
# instead of this
[frobulate(x) for x in seq if frobulate(x) > 0]
# you could have this
[y for x in seq if frobulate(x) as y > 0]
Although I prefer to use an inner map:
[y for y in map(frobulate, seq) if y > 0] # use itertools.imap in Python2
More information about the Python-ideas