[Python-Dev] (name := expression) doesn't fit the narrative of PEP 20 (original) (raw)

Łukasz Langa lukasz at langa.pl
Wed Apr 25 21:52:34 EDT 2018


On 25 Apr, 2018, at 5:20 PM, Chris Angelico <rosuav at gmail.com> wrote:

On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote: Just yesterday this snippet was used on python-dev to show how great the new syntax is:

myfunc(arg, buffer=(buf := [None]*getsize()), size=len(buf)) To my eye this is an anti-pattern. One line of code was saved, but the other line becomes less readable. The fact that 'buf' can be used after that line means that it will be harder for a reader to trace the origin of the variable, as a top-level "buf = " statement would be more visible. Making 'buf' more visible is ONLY a virtue if it's going to be used elsewhere. Otherwise, the name 'buf' is an implementation detail of the fact that this function wants both a buffer and a size.

You're claiming that := is nicer in this situation because it's less prominent than regular assignment and thus doesn't suggest that the name stays visible later.

But as others said, := does make the name visible later until the enclosing scope ends. In fact, a large part of its appeal is that you can use the result later (as in the re.search() example). Will it be visible enough to the reaser in those cases then?

There seems to be a conflict there.

The question of assignment visibility also makes me think about unintentional name shadowing::

buf = some_value

...  # 20 lines

my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))

...  # 20 lines

buf  # <-- What value does this have?

Even if we're not using the call pattern, there can be plenty of logic tests which aren't very obvious::

buf = some_value

...  # 20 lines

if node.parent is not None and (buf := node.parent.buffer):
    ... # 10 lines

...  # 20 lines

buf  # <-- What value does this have?

This is even more interesting because now buf isn't rebound always.

So if I'm confused about an unexpected change in value of buf, I'll skim the code, fail to find the assignment, and then grep for buf = and also fail to find the assignment. Yes, I could have searched for just buf instead but that will give me too many false positives, especially if I'm using a primitive text editor search or don't know about \b in regular expressions.

Debugging this can be confusing. I know it can since a similar annoyance can be observed with the magic pseudo-scope of except::

err = some_value
try:
    ...
except Error as err:
    ...

err  # <-- now sometimes it's not defined

Just like Barry, I debugged a few cases of this in the past and within larger functions this can be hard to find.

-- Ł

-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20180425/9d2fbb9d/attachment.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: Message signed with OpenPGP URL: <http://mail.python.org/pipermail/python-dev/attachments/20180425/9d2fbb9d/attachment.sig>



More information about the Python-Dev mailing list