Does this argument also apply to the if/else expression? Do linters
need rules to advise against people writing code like:
print(x) if x is None else print(y)
? It's perfectly legal to write code like this. But I don't see people
abusing this sort of thing.
ChrisA
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/dev-python%2Bgarchive-30976%40googlegroups.com
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
[Łukasz Langa <luk...@langa.pl>]
> This reads dismissive to me. I did read the PEP and followed the discussion on
> python-dev. I referred to PEP 20 because it distills what's unique about the
> value proposition of Python. It's our shared vocabulary.
>
> Can you address the specific criticism I had? To paraphrase it without PEP 20
> jargon:
> (name := expression) makes code less uniform. It inserts more information
> into a place that is already heavily packed with information (logic tests).
I'll take a crack at that. It's not about "head arguments" at all. I
sat out the first hundred messages about this on python-ideas, and
looked at code instead. What I found had little to do with any of the
head (abstract) arguments passionately debated for the duration ;-)
In real life, I found a great many conditional tests that not only
weren't "heavily packed" with information, they were simply of the
form:
NAME = expression
if NAME:
... use NAME ...
That looks more like assembly language than Python ;-) I saw no harm
at all, and a little gain, in
if NAME := expression:
... use NAME ...
instead. But even a little gain adds up when it happens so often.
Of course there have been better examples given of bigger gains. But
in no case have the tests in those examples been "heavily packed with
information". If they had been, I would have suggested instead
breaking the test clauses _out_ of the conditional statements, and
giving them names each on their own dedicated lines, with comments
explaining what the heck the _intents_ are, even at the cost of adding
an indentation level or two. Sometimes conditionals are _already_ "too
dense". But more often they're very sparse.
This becomes a question of seasoned judgment. For example, here's a
real loop summing a series expansion, until the new terms become so
small they make no difference to the running total (a common enough
pattern in code slinging floats or decimals):
while True:
old = total
total += term
if old == total:
return total
term *= mx2 / (i*(i+1))
i += 2
To my eyes, this is genuinely harder to follow, despite its relative brevity:
while total != (total := total + term):
term *= mx2 / (i*(i+1))
i += 2
return total
So I wouldn't use binding expressions in that case. I don't have a
compelling head argument for _why_ I find the latter spelling harder
to follow, but I don't need a theory to know that I in fact do.
But neither do I need a compelling head argument for "why" to know
that in many other cases I find that the use of binding expressions
improves the code. You shouldn't believe me even if I pretended to
have one and passionately argued for it. But, by the same token, I'm
spectacularly unmoved by other peoples' head arguments.
For that reason, the messages that sway me are those showing real
code, or at least plausibly realistic code. In the majority of those
so far, binding expressions would be a small-to-major win.
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/dev-python%2Bgarchive-30976%40googlegroups.com
> On 25 Apr, 2018, at 1:28 PM, Guido van Rossum <gu...@python.org> wrote:
>
> You don't seem to grasp the usability improvements this will give. I hear you but at this point appeals to Python's "Zen" don't help you.
This reads dismissive to me. I did read the PEP and followed the discussion on
python-dev.
I referred to PEP 20 because it distills what's unique about the
value proposition of Python. It's our shared vocabulary.
Can you address the specific criticism I had? To paraphrase it without PEP 20
jargon:
> (name := expression) makes code less uniform. It inserts more information
> into a place that is already heavily packed with information (logic tests).
Every programming language has a shared vocabulary. That's hardly unique
to Python.
> Can you address the specific criticism I had? To paraphrase it without PEP 20
> jargon:
>
> > (name := expression) makes code less uniform. It inserts more information
> > into a place that is already heavily packed with information (logic tests).
I'm not Guido, but I'll make an attempt.
I think the comment about "less uniform" isn't meaningful. Uniform in
what way?
I don't even know how to interpret the uniform comment here, unless you
mean to imply that every statement and expression in Python currently
has the same information density, and binding-expressions will violate
that. That's clearly not the case, so I'm left puzzled by what you mean.
As for your observation that binding-expressions don't reduce
complexity, they merely move it, I think you may be right. But
then it is a truism that complexity is never reduced, only moved, so
that's likely to be true for any feature (including existing ones).
Should we move back to assembly language programming because Python
hasn't reduced complexity, only moved it? I don't think so.
Clearly binding-expressions do add a little more complexity to the
language, and they do move code from vertically separated statements to
horizontally laid-out expressions.
But why is this necessarily a bad thing? Exactly the same complaint can
be made about comprehensions, and look at how wildly successful they
have been.
Offset against the increase in horizontal complexity is a corresponding
decrease in vertical complexity, and that's beneficial.
Whatever cost they have has to be offset against the benefits, and I
think the feature will come ahead on the plus side overall. Of course,
like any syntactic feature, it may be abused by those who (by accident
or design) write obfuscated or excessively complex code. We shouldn't
ignore that risk, but nor should we use that as an excuse to dismiss the
feature's benefits.
--
Steve
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/dev-python%2Bgarchive-30976%40googlegroups.com
On 04/25/2018 02:55 PM, Tim Peters wrote:
To my eyes, this is genuinely harder to follow, despite its relative brevity:
while total != (total := total + term):
term *= mx2 / (i*(i+1))
i += 2
return total
So I wouldn't use binding expressions in that case. I don't have a
compelling head argument for _why_ I find the latter spelling harder
to follow, but I don't need a theory to know that I in fact do.
I know why I do: I see "while total != total" and my gears start stripping. On the other hand,
while total != (total + term as total):
...
I find still intelligible. (Yes, I know "as" is dead, just wanted to throw that out there.)
On 25 Apr, 2018, at 5:20 PM, Chris Angelico <ros...@gmail.com> wrote:On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
<yseliv...@gmail.com> wrote:Just yesterday this snippet was used on python-dev to show how great the
new syntax is:
my_func(arg, buffer=(buf := [None]*get_size()), 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.
-- Ł
One language feature conspicuous by absence in newbie
confusions was, consistently, assignment expressions. Read any book
or tutorial for such a language, and you'll find very little space
devoted to them too.
What's to learn? If they understand "binding a name" _at all_ (which
they must to even begin to write a non-trivial program), the only
twist is that a binding expression returns the value being bound.
To my eyes, the examples give ample opportunity for beingmisunderstood and will create a need to puzzle-out the intended semantics.
Some do, many don't.
Another way to say this is that expressions are no longer
restricted to being trees, but can be general DAGs, which
require more mental effort to understand.
Hmmm, maybe they should be called "spaghetti expressions". :-)
--
Greg
Is that right? I presume you mean that there can be cycles in
expressions involving binding-expressions. If not, what do you mean?
Can you give an example of a Python expression, involving PEP 572
binding-expressions, that is not a tree but a more general DAG or that
contains cycles?
--
Steve
A DAG is a directed *acyclic* graph, so it still can't contain cycles.
But I have no idea what kind of expression isn't a tree as a
consequence of having an assignment in it.
ChrisA
[Łukasz Langa <luk...@langa.pl>]
> Well, you have an entire code style built around this feature called Yoda
> conditions. You teach people on Day 1 to never ever confuse == with =. Some
> compilers even warn about this because so many people did it wrong.
Sorry, I couldn't follow that. In languages like C that use easily
confused operator symbols, sure, people are forever typing "=" when
they mean "==". That's nothing to do with whether they _understand_
what the different operators do, though. They do. In languages like
Icon (that use "=" for numeric comparison and ":=" for assignment),
that never occurs. But I'm not sure that addressed the point you were
making.
>> What's to learn? If they understand "binding a name" _at all_ (which
>> they must to even begin to write a non-trivial program), the only
>> twist is that a binding expression returns the value being bound.
> Ha, not in Python! Here we have *different syntax* for assignments in
> expressions.
Yes, binding expressions in the current PEP support an extremely
limited subset of what Python's assignment statements support. That
they use different operator symbols is irrelevant to that the meaning
of "binding a name" is exactly the same for both.. _That's_ the "hard
part" to learn.
> Well, you can also use it as a statement. But don't!
Why not? _Every_ expression in Python can be used as a statement.
Nothing forbids it, and that's even (very!) useful at an interactive
prompt.
> We have a better one for that.
As a matter of style, sure, it's best to use the simplest thing that
works. As a statement in a program (as opposed to typed at a shell),
"a := 3" has the unnecessary (in that context) property of returning
(and discarding 3), so it's better style to use "a = 3" in that
context.
> And that one supports type annotations, can unpack and assign to many
> targets at the same time, and can even increment, multiply and so on, at once.
> But the other one can't.
So? math.sqrt() blows up when passed -1, but cmath.sqrt() doesn't.
Different tools for different tasks.
> So only use the Pascal one in expressions. But don't forget parentheses,
> otherwise it will bind the thing you probably didn't want anyway.
[Raymond]
>>> To my eyes, the examples give ample opportunity for being
>>> misunderstood and will create a need to puzzle-out the intended
>>> semantics.
>> Some do, many don't.
> As soon as we have to wrap a part of an expression in parentheses, parsing
> the entire thing becomes more complex. Often enough it will cause the
> expression to exceed whatever line length limit the codebase pledged not to
> exceed, causing one line to become three. And again, making it trickier for
> a regular Łukasz to understand what's going on.
At this point I think you must have a lower opinion of Python
programmers than I have ;-) If adding even a dozen characters to a
line makes it exceed a reasonable line-length guide, the code was
almost certainly too confusingly dense to begin with. All the
binding-expression examples I've given as "improvements" had _oceans_
of horizontal white space to swim in.
Guido's if/elif/elif/elif/ ... complex text-processing example didn't,
but because the current lack of an ability to bind-and-test in one
gulp forced the `elif` parts to be ever-more-deeply-indented `if`
blocks instead.
So, to match your sarcasm, here's mine: try using a feature for what
it's good at instead of for what it's bad at ;-)
> So only use the Pascal one in expressions. But don't forget
> parentheses, otherwise it will bind the thing you probably didn't want
> anyway.
Binding expressions are no worse than any other expression: sometimes
you need to bracket terms to change the default precedence, and
sometimes you don't.
And sometimes, even if we don't *need* parens, we use them anyway
because it makes the expression easier to read and understand.
Unless you have a language with no operator precedence at all, a purely
left-to-right evaluation order like Forth or (I think?) APL, there will
always be circumstances where parens are needed. Criticising binding-
expressions for that reason, especially implying that we must always use
parens, is simply FUD.
[...]
> As soon as we have to wrap a part of an expression in parentheses,
> parsing the entire thing becomes more complex.
Unless it becomes less complex to read and understand.
I for one always have difficulty parsing complex boolean tests unless I
bracket some or all of the parts, even when they're not strictly needed.
Consequently I try very hard not to write complex bool tests in the
first place, but when I can't avoid it, a few extra brackets really
helps simplify the logic.
> Often enough it will
> cause the expression to exceed whatever line length limit the codebase
> pledged not to exceed, causing one line to become three.
Just how often are your lines within two characters of the maximum
column so that adding a pair of brackets () will "often enough" put it
over the limit? Seems pretty unlikely to me. This sounds really like
picking at straws.
--
Steve
This is what I least like about the proposal. We should
be moving in the direction of removing warts, but here
we would be *creating* one (two different assignment
operators with overlapping use cases) that we won't be
able to get rid of without a Python 4000 (that Guido has
promised won't happen).
--
Greg
Not only, but seeing `:=` hints that something *special* is going on
(some inner expression is being bound to a name). So now we have to be
extra careful when reading and reviewing code written that people who
like using that syntactical feature.
I also wonder how long it will be before someone writes:
def f(arg):
global _lazy_value
if predicate(arg) and (_lazy_value := frobnicate()) > arg:
...
(or something similar with "nonlocal")
Regards
Antoine.
> On Thu, Apr 26, 2018 at 05:22:58PM +1200, Greg Ewing wrote:
> > Łukasz Langa wrote:
> > >What was its own assignment before
> > >now is part of the logic test. This saves on vertical whitespace but makes
> > >parsing and understanding logic tests harder.
> >
> > Another way to say this is that expressions are no longer
> > restricted to being trees, but can be general DAGs, which
> > require more mental effort to understand.
>
> Is that right? I presume you mean that there can be cycles in
> expressions involving binding-expressions. If not, what do you mean?
>
> Can you give an example of a Python expression, involving PEP 572
> binding-expressions, that is not a tree but a more general DAG or that
> contains cycles?
Depends if you mean a graph between names or values?
If between names, you can even have cycles AFAICT:
((a: = a + b), (b: = a))
Regards
Antoine.
> On 25 Apr, 2018, at 1:28 PM, Guido van Rossum <gu...@python.org> wrote:
>
> You don't seem to grasp the usability improvements this will give. I hear you but at this point appeals to Python's "Zen" don't help you.
This reads dismissive to me. I did read the PEP and followed the discussion on
python-dev. I referred to PEP 20 because it distills what's unique about the
value proposition of Python. It's our shared vocabulary.
Can you address the specific criticism I had? To paraphrase it without PEP 20
jargon:
> (name := expression) makes code less uniform. It inserts more information
> into a place that is already heavily packed with information (logic tests).
On Thu, Apr 26, 2018 at 03:31:13AM -0400, Terry Reedy wrote:
> On 4/25/2018 8:20 PM, Chris Angelico wrote:
> >On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
> ><yseliv...@gmail.com> wrote:
> >>Just yesterday this snippet was used on python-dev to show how great the
> >>new syntax is:
> >>
> >> my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>
> What strikes me as awful about this example is that len(buf) is
> get_size(), so the wrong value is being named and saved.
> 'size=len(buf)' is, in a sense, backwards.
Terry is absolutely right, and I'm to blame for that atrocity. Mea
culpa.
> 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.
FWIW, I read what he wrote as "*assuming* buf is not going to be used
later", and thus took a more nuanced idea from it: Use a separate
statement when you do use it later, and use a binding expression when
its scope is *in fact* only that line.
BTW, I don't find the "it could be misused, so it will be misused"
argument persuasive. I agree it's true, but don't think it matters,
per the "consenting adults" principle, since binding expressions have
other, important, use cases.
We could add a statement to PEP 8 mildly deprecating this particular
use. How about this:
In some examples, the binding expression is used in function
arguments where one argument depends on an earlier one, such as
foo(buffer=(buf := [None]*get_size()), size=len(buf))
In examples like this one, it is preferable where possible to
refactor the function to calculate the dependent variable itself,
or to use an assignment statement to define the bound variable.
The latter style is *strongly* preferred when the bound variable
will be used later in the scope.
Steve
[Raymond Hettinger <raymond....@gmail.com>]
> Python is special, in part, because it is not one of those languages.
> It has virtues that make it suitable even for elementary school children.
> We can show well-written Python code to non-computer folks and walk
> them through what it does without their brains melting (something I can't
> do with many of the other languages I've used). There is a virtue
> in encouraging simple statements that read like English sentences
> organized into English-like paragraphs, presenting itself like
> "executable pseudocode".
Yes, binding expressions in the current PEP support an extremely
limited subset of what Python's assignment statements support.[...]
The PEP has more examples with parentheses than without.
>> As soon as we have to wrap a part of an expression in parentheses,
>> parsing the entire thing becomes more complex.
>
> Unless it becomes less complex to read and understand.
You're ignoring the context of the discussion. The new parentheses are there because there's a new assignment there. That's more complex.
>> Often enough it will
>> cause the expression to exceed whatever line length limit the codebase
>> pledged not to exceed, causing one line to become three.
>
> Just how often are your lines within two characters of the maximum
> column so that adding a pair of brackets () will "often enough" put it
> over the limit? Seems pretty unlikely to me.
Again, you're ignoring the context of the discussion. Assuming := will have spaces around it in PEP 8, this is adding *at least* 7 characters if the name of your choice is a single character.
> This sounds really like
> picking at straws.
The entire point of the PEP is to make things "nicer". It doesn't fundamentally enable programmers to do anything they couldn't do before.
If you think demonstrating cases where the end result won't be an improvement is picking at straws, then maybe the improvement of PEP 572 is as well.
-- Ł
Yes, this is the fundamental wisdom. Judging which is which is left as an
exercise to the programmer.
With this, I'm leaving the discussion. With Guido and you on board for PEP
572, I feel that Chris' streak is indeed about to break.
Some parting hair-splitting follows.
> [Uncle T]
>>> One language feature conspicuous by absence in newbie
>>> confusions was, consistently, assignment expressions. Read any book
>>> or tutorial for such a language, and you'll find very little space
>>> devoted to them too.
>
> [Łukasz Langa <luk...@langa.pl>]
>> Well, you have an entire code style built around this feature called Yoda
>> conditions. You teach people on Day 1 to never ever confuse == with =. Some
>> compilers even warn about this because so many people did it wrong.
>
[Uncle T]
> Sorry, I couldn't follow that.
You implied that newbies don't have to even know about assignments in
expressions. I wanted to demonstrate that this isn't really the case because
mistaking `=` for `==` is a relatively common occurence for newbies. If you
want to argue that it isn't, I'd like to point out that the WordPress code
style *requires* Yoda conditions because it was enough of a hindrance. ESLint
(a JavaScript linter) also has a warning about assignment in a conditional.
[Uncle T]]
> In languages like C that use easily
> confused operator symbols, sure, people are forever typing "=" when
> they mean "==". That's nothing to do with whether they _understand_
> what the different operators do, though.
What you're saying is true. But for it to be true, newbies *have to* learn the
distinction, and the fact that yes, sometimes the programmer indeed meant to
put a single `=` sign in the conditional. That's why we'll end up with the
Pascal assignment operator. And that *is* a thing that you will have to
explain to newbies when they encounter it for the first time. Sadly, googling
for a colon followed by an equal sign isn't trivial if you don't know what
you're looking for.
[Łukasz]
>> Well, you can also use it as a statement. But don't!
>
[Uncle T]]
> Why not? _Every_ expression in Python can be used as a statement.
> Nothing forbids it, and that's even (very!) useful at an interactive
> prompt.
Because it suggests different intent, because it's limited, because it's slower
at runtime, and because PEP 572 says so itself.
> At this point I think you must have a lower opinion of Python
> programmers than I have ;-) If adding even a dozen characters to a
> line makes it exceed a reasonable line-length guide, the code was
> almost certainly too confusingly dense to begin with.
Around 5% of if and elif statements in the standard library don't fit a single
line *as is*. Sure, that's a low percentage but that's over 1,000 statements.
If you're putting an `if` statement in a method, you are already starting out
with 71 characters left on the line. Four of those are going to be taken by
"if", a space, and the colon. Adding a parenthesized assignment expression
takes at least 10% of that available space.
The silver lining for me is that this makes the environment riper for
auto-formatting.
That is exactly what I wrote in the continuation that Steven snipped.
--
Terry Jan Reedy
Ugh! The only reason I would bother typing the : in a top level
assignment would be to get the print without having to retype the name,
as in
>>> x = expr
>>> x
I consider echoing top-level interactive assignments to be a feature of
the proposal.
--
Terry Jan Reedy
[Lukasz Langa <luk...@langa.pl>]
> Yes, this is the fundamental wisdom. Judging which is which is left as an
> exercise to the programmer.
>
> With this, I'm leaving the discussion. With Guido and you on board for PEP
> 572, I feel that Chris' streak is indeed about to break.
I still expect it could go either way, but do wish people didn't
believe it will be a major loss if "the other side wins". I'll be
fine regardless - and so will everyone else. Guido rarely makes
language design mistakes. In this case he's seeing serious opposition
from several core developers, and you shouldn't believe either that he
just dismisses that.
[Łukasz Langa]
>>> Well, you have an entire code style built around this feature called Yoda
>>> conditions. You teach people on Day 1 to never ever confuse == with =. Some
>>> compilers even warn about this because so many people did it wrong.
>> Sorry, I couldn't follow that.
Part of the problem here is that I had never seen "Yoda conditions"
before, and had no idea what it meant. Some later Googling suggests
it's "a thing" youngsters say at times ;-)
> You implied that newbies don't have to even know about assignments in
> expressions. I wanted to demonstrate that this isn't really the case because
> mistaking `=` for `==` is a relatively common occurence for newbies. If you
> want to argue that it isn't, I'd like to point out that the WordPress code
> style *requires* Yoda conditions because it was enough of a hindrance. ESLint
> (a JavaScript linter) also has a warning about assignment in a conditional.
What does that have to do with Python? If they try to use "=" in an
expression now, they get a SyntaxError. The PEP doesn't change
anything about that. Indeed, that's why it uses ":=" instead. I have
experience in other languages with embedded assignments that also use
":=", and it's _never_ the case that people type ":=" when they intend
"equality test" in those. The horrid "I typed = when I meant =="
mistakes are unique to languages that mindlessly copied C. The
mistakes aren't primarily due to embedded assignments, they're due to
that even highly experienced programmers sometimes type "=" when
they're _thinking_ "equals". Nobody types ":=" when they're thinking
"equals".
> ...
> What you're saying is true. But for it to be true, newbies *have to* learn the
> distinction, and the fact that yes, sometimes the programmer indeed meant to
> put a single `=` sign in the conditional.
Again, the PEP is about Python: a single "=" in a conditional is, and
will remain, a SyntaxError. So nobody can sanely intend to put a
single "=" in a condition _in Python_ unless they're writing a test
intending to provoke a syntax error.
> That's why we'll end up with the Pascal assignment operator.
":=" is already in the PEP.
> And that *is* a thing that you will have to explain to newbies when they encounter
> it for the first time.
Sure. That doesn't frighten me, though. It's easy to explain what it
does - although it may be hard to explain when it's _desirable_ to use
it.
> Sadly, googling for a colon followed by an equal sign isn't trivial if you don't
> know what you're looking for.
To judge from Stackoverflow volume, the single most misunderstood of
all Python operators - by far - is "is" - try Googling for that ;-)
In far second and third places are "and" and "or", for which searches
are also useless.
Regardless, I'm not concerned about one-time tiny learning curves.
Don't know what ":=" means already? Ask someone. If you know what
"=" means, you're already close to done. Given that you already
understand what "binding a name" means, ":=" may well be the simplest
of all Python's operators (there's no computation _to_ be understood,
and no possibility either of a dunder method changing its meaning
depending on operand type(s)).
>>> Well, you can also use it as a statement. But don't!
>> Why not? _Every_ expression in Python can be used as a statement.
>> Nothing forbids it, and that's even (very!) useful at an interactive
>> prompt.
> Because it suggests different intent, because it's limited, because it's slower
> at runtime, and because PEP 572 says so itself.
I didn't say you're _required_ to use it as a statement. Regardless
of what PEPs say, people will do what they find most useful. I trust
people to figure this out quickly for themselves.
>> At this point I think you must have a lower opinion of Python
>> programmers than I have ;-) If adding even a dozen characters to a
>> line makes it exceed a reasonable line-length guide, the code was
>> almost certainly too confusingly dense to begin with.
> Around 5% of if and elif statements in the standard library don't fit a single
> line *as is*. Sure, that's a low percentage but that's over 1,000 statements.
> If you're putting an `if` statement in a method, you are already starting out
> with 71 characters left on the line. Four of those are going to be taken by
> "if", a space, and the colon. Adding a parenthesized assignment expression
> takes at least 10% of that available space.
Confirming that you do have a lower opinion of them ;-) Are you
picturing people stampeding to introduce ":=" in every place they
possibly could? I may be wrong, but I don't expect that at all. I
expect a vast majority of uses in real life will replace:
name = expression
if name:
by
if name := expression:
and
while True:
name = expression
if name comparison expression2:
break
by
while (name := expression) inverted_comparison expression2:
_provided that_ the latter spelling doesn't make the line
uncomfortably long. In all the code of mine I've seen a good use for
it, there's a whole lot of empty horizontal screen space to spare,
even after recoding. In places where I already had "long lines", I
didn't even check to see whether a binding operation could be used too
- why would I? I don't feel _compelled_ to use it - I'm only looking
to reduce redundancy where it's an obvious win.
> The silver lining for me is that this makes the environment riper for
> auto-formatting.
See? It's win-win for you too no matter how this turns out ;-)
my_func(arg, buffer=[None]*get_size() as buf, size=buf)
Yes? Parens aren't mandatory, and my point that other operators also
sometimes needs parens still holds.
> >> As soon as we have to wrap a part of an expression in parentheses,
> >> parsing the entire thing becomes more complex.
> >
> > Unless it becomes less complex to read and understand.
>
> You're ignoring the context of the discussion. The new parentheses are
> there because there's a new assignment there. That's more complex.
I'm not ignoring the context of the discussion. I'm comparing binding-
expression with and without parens. That's what I thought you were
doing.
If that wasn't your intended meaning, then I apologise but please
understand why I answered the way I did.
I still stand by my argument: parens are not always needed, and even
when they are not needed, adding them can sometimes make things
*easier* and *less complex* to read.
[...]
> If you think demonstrating cases where the end result won't be an
> improvement is picking at straws, then maybe the improvement of PEP
> 572 is as well.
Any feature can have cases where the end result is worse than not using
the feature. That *alone* isn't a strong argument against a feature.
Do you have much existing code using binding expressions? Of course not.
Will you be adding them to code that already exists? Probably not -- you
can't do so until you are using 3.8 at minimum, and if your code needs
to be backwards compatible, you can't use it until you've dropped
support for 3.7 and older. That might not be for five or ten years.
So it is likely that for most people only new code will use this
feature. It is not reasonable to say that if I have existing code like
this:
spam = expression
if long_condition_that_takes_up_most_of_the_line == spam or spam:
...
that I'm going to immediately change it to a one-liner:
if long_condition_that_takes_up_most_of_the_line == (spam := expression) or spam:
...
and push it over the maximum line width. With or without parentheses.
Why would I do something so silly? Using binding expressions isn't
mandatory and most coders don't intentionally do things that make their
code worse.
And if I wouldn't change existing code and push it over the limit, why
would I write new code that does it? Especially when there are much
better alternatives:
if (long_condition_that_takes_up_most_of_the_line
== (spam:=expression)
or spam):
...
We have a history of adding features that can be abused, but aren't.
People hardly ever abuse list comps with overly long and complex
multiple-loop comprehensions:
[... for a in sequence for b in something for c in another for d in something_else]
I'm sure we've all seen one or two of those. But it doesn't happen
enough to matter. Same with if...elif...else chains. People didn't
immediately run out and replace every single if chain into nested
ternary if expressions, pushing their lines out to beyond the maximum
line width:
expression if condition else (expression if condition else (expression if condition else (expression if condition else expression)))
Real people don't abuse comprehensions or ternary if enough for us to
regret adding them to the language. I'm sure that they won't abuse this
feature either. The Python community simply doesn't have the culture of
abusing syntax in this way and writing overly dense one-liners, and I
don't think it is reasonable to say this feature will tip the balance.
It is reasonable to say that *some* code will be made worse by this,
because there's always *someone* who will abuse syntax. There are those
who insist on writing list comprehensions for their side-effects:
# return and throw away a list of Nones
[print(item) for item in bunch_of_stuff]
but I don't think this happens enough to make us regret adding
comprehensions to the language.
--
Steve
> And that *is* a thing that you will have to explain to newbies when they encounter
> it for the first time.
Sure. That doesn't frighten me, though. It's easy to explain what it
does - although it may be hard to explain when it's _desirable_ to use
it.
To judge from Stackoverflow volume, the single most misunderstood of
all Python operators - by far - is "is" -
On Fri, Apr 27, 2018 at 8:18 PM, Wes Turner <wes.t...@gmail.com> wrote:
> IDK, I could just be resistant to change, but this seems like something that
> will decrease readability -- and slow down code review -- without any real
> performance gain. So, while this would be useful for golfed-down (!)
> one-liners with pyline,
> I'm -1 on PEP 572.
PEP 572 has never promised a performance gain, so "without any real
performance gain" is hardly a criticism.
> How do I step through this simple example with a debugger?
>
> if re.search(pat, text) as match:
> print("Found:", match.group(0))
Step the 'if' statement. It will call re.search() and stash the result
in 'match'. Then the cursor would be put either on the 'print' (if the
RE matched) or on the next executable line (if it didn't).
> From https://en.wikipedia.org/wiki/Assignment_(computer_science) :
>
>> In some languages the symbol used is regarded as an operator (meaning that
>> the assignment has a value) while others define the assignment as a
>> statement (meaning that it cannot be used in an expression).
>
>
> PEP 572 -- Assignment Expressions
> PEP 572 -- Assignment Operator (:=) and Assignment Expressions
Huh? I don't get your point.
ChrisA
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/wes.turner%40gmail.com
ChrisA
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/wes.turner%40gmail.com
[Chris Angelico <ros...@gmail.com>]
> ...
> I don't understand why people bring up all these arguments that have
> absolutely nothing to do with the proposal at hand. None of this has
> in any way changed.
That's easy: any time there's a long thread to which Guido has
contributed at least twice, it will be seen as a Golden Opportunity to
re-litigate every decision that's ever been made ;-)
Some amount of that seems healthy to me (people are thinking about
"language design" from a larger view than the proposal du jour). In
this specific case, line-oriented coverage tools have missed
accounting for all possible code paths since day #1; e.g.,
x = f() or g()
You don't need to reply to messages so obviously irrelevant to the PEP
unless you want to. It's not like Guido will read them and go "oh! a
binding expression in a ternary conditional is a fundamentally new
potential problem for a line-oriented coverage tool! that's fatal"
;-)
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/wes.turner%40gmail.com
That's easy: any time there's a long thread to which Guido has
contributed at least twice, it will be seen as a Golden Opportunity to
re-litigate every decision that's ever been made ;-)
On 26 April 2018 at 07:50, Raymond Hettinger
<raymond....@gmail.com> wrote:
>> [Raymond Hettinger <raymond....@gmail.com>]
>>> After re-reading all the proposed code samples, I believe that
>>> adopting the PEP will make the language harder to teach to people
>>> who are not already software engineers.
>
> (...)
>
> Python is special, in part, because it is not one of those languages.
> It has virtues that make it suitable even for elementary school children.
> We can show well-written Python code to non-computer folks and walk
> them through what it does without their brains melting (something I can't
> do with many of the other languages I've used). There is a virtue
> in encouraging simple statements that read like English sentences
> organized into English-like paragraphs, presenting itself like
> "executable pseudocode".
I must admit that when I heard about this PEP I thought "this April
1st joke was already done long ago". I'm sorry to discover that, this
time, it is not actually one. Thank you, Raymond, for an unlikely
attempt at reminding people what made Python so special---in your
opinion, and mine.
A bientôt,
Armin.
Hi,
On 26 April 2018 at 07:50, Raymond Hettinger
<raymond....@gmail.com> wrote:
>> [Raymond Hettinger <raymond....@gmail.com>]
>>> After re-reading all the proposed code samples, I believe that
>>> adopting the PEP will make the language harder to teach to people
>>> who are not already software engineers.
>
> (...)
>
> Python is special, in part, because it is not one of those languages.
> It has virtues that make it suitable even for elementary school children.
> We can show well-written Python code to non-computer folks and walk
> them through what it does without their brains melting (something I can't
> do with many of the other languages I've used). There is a virtue
> in encouraging simple statements that read like English sentences
> organized into English-like paragraphs, presenting itself like
> "executable pseudocode".
I must admit that when I heard about this PEP I thought "this April
1st joke was already done long ago". I'm sorry to discover that, this
time, it is not actually one. Thank you, Raymond, for an unlikely
attempt at reminding people what made Python so special---in your
opinion, and mine.
A bientôt,
Armin.
[Lukasz]
>> > And that *is* a thing that you will have to explain to newbies when
>> > they encounter it for the first time.
[...]
Sure. What I wrote was shorthand for what's already been covered at
length many times: what a binding expression does is "easy to
explain" GIVEN THAT someone ALREADY UNDERSTANDS how binding a name
works. The latter in fact seems difficult for a significant number of
people to learn, but it's utterly unavoidable that they learn it if
they're ever to write non-trivial Python programs. That's been true
since Python's first release.
Binding expressions would be introduced much later in any sane course.
At THAT point, for students who haven't already dropped out, the
semantics are darned-near trivial to explain: it binds the name to
the object the expression evaluates to (all of which they _already_
understand by this point), and the value of the binding expression is
that object (the only new bit).
Unlike as for most other operators, you don't even have to weasel-word
it to account for that a magical dunder method may change what ":="
does. As for the "is" operator, the meaning is baked into the
language and can't be altered in the slightest.
> So having one more way to do assignment WILL make it harder to
> teach, not because it's that hard, but because it's one more thing to learn.
[...]
> You now, I think instructors like me are partly responsible. "is" is rarely
> useful outside of comparing to singletons. Yet I use it early in instruction
> to do checks on name binding and show things with mutablilty, etc.... which
> has the unfortunate side effect of making it seem like a more common
> operator than it is.
>
> I've even had students write code like:
>
> if x is 3:
>
> and thanks to interning, it appears to work!
Yup, that's the real problem with "is": its semantics are dead
simple, but "but under exactly what conditions are `x` and `y` bound
to the same object?" is intractable. It seems to take a long time to
get across the point, that the question itself is misguided. A full
answer requires delving into transient implementation details, which
is counterproductive because they _are_ accidents of the
implementation du jour. What questioners need to be nudged into
asking instead is for examples of when using "is" is thoroughly sane.
Coverage.py can measure branch coverage, but it is still line-oriented.
There's no support for conditionals and branches within a line (though
I've done some wicked hacks to experiment with it:
https://nedbatchelder.com/blog/200804/wicked_hack_python_bytecode_tracing.html).
It's entirely true that binding expressions don't change this situation
at all, EXCEPT that the entire point of binding expressions is to be
able to express in one statement what used to take more than one. With
binding expressions, actions may be coverage-hidden within one statement
that without them would have been coverage-visible in more than one
statement.
I'm not sure that's an argument against binding expressions, but we
should at least acknowledge that the motivation for them is to provide
the option to write fewer, longer statements. That option is not always
a good idea, for a variety of reasons.
--Ned.