Python 3.8.0a1 is now available for testing
pythoninsider.blogspot.com
pythoninsider.blogspot.com
I personally think it's quite a nifty feature. I often end up writing something along the lines of:
result = do_something()
if result:
do_more(result)
Now that can be expressed as: if result := do_something():
do_more(result)
It definitely has the potential to be abused and reduce readability, but applied well I think it can increase readability.[1] https://www.python.org/dev/peps/pep-0572/#relative-precedenc... [2] https://mail.python.org/pipermail/python-committers/2018-Jul...
It's very exciting to remove these sorts of redundant lines, but I cannot train my brain to intuitively view that line as it will be interpreted.
There is one case where the benefit, IMHO, far outweighs the negatives, and that can be seen in slides 30-31 of Dustin Ingram's slideshow[1].
PEP 572... the day Python jumped the walrus.
1. https://speakerdeck.com/di_codes/pep-572-the-walrus-operator...
Something that is unnatural, such as an operator mixed with an expression is anything but natural, in the context of Python.
I can force myself to recognize the pattern; yes.
Also, the example I linked to in the slide show does feel somewhat intuitive (usage in a while loop).
Direct link: https://speakerd.s3.amazonaws.com/presentations/025e2c4bf551... (s/preview_// for a larger version)
Any C program can be written as a single line, with no linebreaks - that doesn't make it "better" by any metric.
Python is built around its readability, and slide 44:
> group = match.group(1) if (match := re.match(data)) else None
is anything but. 'match' is assigned after its first use, and it took me far to long to mentally parse what it was doing.
Even if you accept that there is some continuum of "...ability" of these things, it's completely arbitrary and unique to everyone as to where the line between "this should be in" and "this should be out" lies.
(In fact he's just been elected to the five-member council that has taken over that role.)
Unfortunately "as …" had a few drawbacks in rare use cases (:= has only aesthetic drawbacks), but I think as was by far the most consistent, readable choice and supported ~90% of use cases.
As for the controversy, that's what happens when you reverse 25 year-old design decisions. Shouldn't be too surprising.
if a := 1 or b := 0:
return a + b
Good luck debugging why this doesn’t work. if (a := 1) or (b := 1):
print(locals())
since a is truthy, it gets bound and is in scope, whereas b is not, which makes sense to me.So are you arguing that the language should not have short-circuit or-statements?
That just seems like you are sacrificing tons of usability only to slightly improve on the expectations of those who are just starting python, like the first 1-2weeks of trying to learn it.
[func(x) for x in values if func(x) < 10]
You could break this into two comprehensions, sure, but it's annoying. With this: [result for x in values if (result := func(x)) < 10]I literally cannot read C code that does this, now I'm going to have to worry about encountering unreadable Python code.
Edit: Also, it violates both "explicit is better than implicit" and "there should be one and only one right way to do it". It's inherently Unpythonic.
outputs = [f(x) for x in inputs]
Versus: outputs = []
for x in inputs:
outputs.append(f(x))
The assignment expression lets you: outputs = [y for x in inputs
if (y := f(x)) is not None]
I know that more complicated list comprehensions in Python are a bit of a sore point for some people, but I would say that they’re also inherently unpythonic, and I like them. outputs = [y for x in inputs
if (y := f(x)) is not None]
I can't stand this new syntax, y is declared and assigned after the first instance of its use.Hogwash. You choose to not.
`if foo == true:`
as
`if foo = true:`
which results in horrible subtle bugs
namedtuple attr access is also now 1.7x faster https://github.com/python/cpython/pull/10495
Other performance improvments : https://github.com/python/cpython/pulls?q=is%3Apr+sort%3Aupd...
# You can now write
if (match := pattern.search(data)) is not None:
# Do something with match
# or even
[y for x in data if (y := f(x)) is not None]
This is what I personally very much anticipated.Also nice:
# This is now supported.
x: Tuple[int, int] = 1, 2 # No parens.
yield 1, 2, 3, *rest # No parens again.
[PEP-572]: https://www.python.org/dev/peps/pep-0572/For years,I've been holding my breath in Python for sum types, totality checking, and an enforced, complete type system -- one where you can say "this should be a list of lists of integers" and it won't let you put any other kind of thing there.
(Yes, there are external typing solutions like PyPy, but last I checked they did not offer complete type systems (you could specify that something is a list, but not that it's a list of ints), nor did they permit totality checking (so if type X is a sum type with two constructors X1 and X2, and f is a function that takes an X as input, and you forgot to define what happens if f is given an X2, it would not know to complain that you hadn't covered all possibilities).
Python type annotations do support such use case: List[int].
What about functions, and functions of functions, etc? Can I specify that the argument to function f should be some other function g which should receive a list of ints and return a dict of functions with keys that are ints and values that are functions from int to int?
>>> def f (x:int) -> int: return x+1
...
>>> def g (x:str) -> str: return f(x)
...
>>> g(1)
2
I expected a complaint after the second definition: I specified that g takes and returns a string, and then defined it to take and return an int. Not only did Python not catch the error at compile time (defining g), it didn't even catch it at runtime (calling g).You are looking at the wrong language.
That said, the array module has been around for ages, for performance reasons.
I hope that 2019 is the year of PyPy adoption, as folks get ready to leave CPython.
[0] https://morepypy.blogspot.com/2016/08/pypy-gets-funding-from...