[Python-ideas] if expensive_computation() as x:

Nick Coghlan ncoghlan at gmail.com
Sat Feb 15 02:40:25 CET 2014


On 15 February 2014 11:22, Chris Angelico <rosuav at gmail.com> wrote:
> On Sat, Feb 15, 2014 at 12:12 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> On 15 February 2014 10:49, Chris Angelico <rosuav at gmail.com> wrote:
>>> And that's my point. No matter how the *computer* sees them, the
>>> *programmer* sees them as peers. Adding an additional option to the
>>> list should not change the indentation level of any other, because the
>>> logical structure of the code hasn't changed.
>>
>> You snipped the salient point in all this: the relevant case is one
>> where the programmer wants to check *different* things, and *only*
>> wants to calculate them if the earlier things are false. If they were
>> true peers, this approach would work:
>>
>>     x = alternative_1()
>>     y = alternative_2()
>>     z = alternative_3()
>>
>>     if x:
>>         # Do something with x
>>     elif y:
>>         # Do something with y
>>     elif z:
>>         # Do something with z
>
> I believe they're still peers; they just happen to be unable to fit
> into the physical structure of Python that way. Her's a concrete
> example: You have a series of regular expressions, and you want to
> process whichever one matches. No line of text is allowed to match
> more than one regex (to prevent excessive processing), but any line
> could match any regex.
>
> if re1.match(line) as match:
>     # do stuff with the match object
> elif re2.match(line) as match:
>     # do different stuff, using the matched substrings
> # etc etc etc

This use case is a large part of why the "first" PyPI project exists
and why itertools.first_true has been proposed for inclusion in the
stdlib: http://bugs.python.org/issue18652 (a patch would help greatly
in getting that to actually happen for 3.5)

The re.match case would then be written as:

    match = first_true(pattern.match for pattern in patterns)

If the handling is identical, there's no need for an if/elif chain at
all, otherwise the revised if/elif chain is based on the attributes of
the match object.

> Adding another one is as simple as determining its position in the
> sequence (since earlier matches take precedence over later ones).

And with first_true, it's similarly simple (especially in the case
where the patterns are different, but the handling is predominantly
the same, since then it's just a matter of adding a new entry to the
list of patterns).

> Removing one is just deleting its elif and corresponding block of
> code. They are peers. The fact that Python doesn't currently have
> syntax that allows this *in an elif chain* doesn't change this; if you
> were to write it as pseudo-code, you would write them as peers. That's
> why the function-with-return or loop-with-break still looks better,
> because it structures the code the way that logically makes sense -
> flat, not nested.

That doesn't mean embedded assignments are the answer though - they're
a sledgehammer solution that is tempting as a workaround for larger
structural issues.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list