[Python-ideas] Combining test and assignment

Steven D'Aprano 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':
     frobulate(spam())


Then I would apply DRY and factor out the call to spam:

x = spam()
if x != 'ham':
     frobulate(x)


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':
     frobulate(x)

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:
     frobulate(x)
     glommify(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



-- 
Steven



More information about the Python-ideas mailing list