[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
- Previous message (by thread): [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20
- Next message (by thread): [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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>
- Previous message (by thread): [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20
- Next message (by thread): [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]