mirror of
https://github.com/python/cpython.git
synced 2025-12-11 11:31:05 +00:00
bpo-37759: First round of major edits to Whatsnew 3.8 (GH-15127)
This commit is contained in:
parent
1213123005
commit
4f9ffc9d1a
2 changed files with 169 additions and 37 deletions
|
|
@ -42,21 +42,25 @@
|
||||||
This saves the maintainer the effort of going through the Mercurial log
|
This saves the maintainer the effort of going through the Mercurial log
|
||||||
when researching a change.
|
when researching a change.
|
||||||
|
|
||||||
This article explains the new features in Python 3.8, compared to 3.7.
|
:Editor: Raymond Hettinger
|
||||||
|
|
||||||
|
This article explains the new features in Python 3.8, compared to 3.7.
|
||||||
For full details, see the :ref:`changelog <changelog>`.
|
For full details, see the :ref:`changelog <changelog>`.
|
||||||
|
|
||||||
.. note::
|
Prerelease users should be aware that this document is currently in
|
||||||
|
draft form. It will be updated as Python 3.8 moves towards release, so
|
||||||
|
it's worth checking back even after reading earlier versions. Some
|
||||||
|
notable items not yet covered are:
|
||||||
|
|
||||||
Prerelease users should be aware that this document is currently in draft
|
* :pep:`578` - Runtime audit hooks for potentially sensitive operations
|
||||||
form. It will be updated substantially as Python 3.8 moves towards release,
|
* ``python -m asyncio`` runs a natively async REPL
|
||||||
so it's worth checking back even after reading earlier versions.
|
|
||||||
|
|
||||||
Some notable items not yet covered here:
|
.. testsetup::
|
||||||
|
|
||||||
* :pep:`578` - Runtime audit hooks for potentially sensitive operations
|
from datetime import date
|
||||||
* ``python -m asyncio`` runs a natively async REPL
|
from math import cos, radians
|
||||||
* ...
|
import re
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
Summary -- Release highlights
|
Summary -- Release highlights
|
||||||
|
|
@ -76,12 +80,43 @@ New Features
|
||||||
Assignment expressions
|
Assignment expressions
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
There is new syntax (the "walrus operator", ``:=``) to assign values
|
There is new syntax ``:=`` that assigns values to variables as part of a larger
|
||||||
to variables as part of an expression. Example::
|
expression. It is affectionately known as "walrus operator" due to
|
||||||
|
its resemblance to `the eyes and tusks of a walrus
|
||||||
|
<https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg>`_.
|
||||||
|
|
||||||
|
In this example, the assignment expression helps avoid calling
|
||||||
|
:func:`len` twice::
|
||||||
|
|
||||||
if (n := len(a)) > 10:
|
if (n := len(a)) > 10:
|
||||||
print(f"List is too long ({n} elements, expected <= 10)")
|
print(f"List is too long ({n} elements, expected <= 10)")
|
||||||
|
|
||||||
|
A similar benefit arises during regular expression matching where
|
||||||
|
match objects are needed twice, once to test whether a match
|
||||||
|
occurred and another to extract a subgroup::
|
||||||
|
|
||||||
|
discount = 0.0
|
||||||
|
if (mo := re.search(r'(\d+)% discount', advertisement)):
|
||||||
|
discount = float(mo.group(1)) / 100.0
|
||||||
|
|
||||||
|
The operator is also useful with while-loops that compute
|
||||||
|
a value to test loop termination and then need that same
|
||||||
|
value again in the body of the loop::
|
||||||
|
|
||||||
|
# Loop over fixed length blocks
|
||||||
|
while (block := f.read(256)) != '':
|
||||||
|
process(block)
|
||||||
|
|
||||||
|
Another motivating use case arises in list comprehensions where
|
||||||
|
a value computed in a filtering condition is also needed in
|
||||||
|
the expression body::
|
||||||
|
|
||||||
|
[clean_name.title() for name in names
|
||||||
|
if (clean_name := normalize('NFC', name)) in allowed_names]
|
||||||
|
|
||||||
|
Try to limit use of the walrus operator to clean cases that reduce
|
||||||
|
complexity and improve readability.
|
||||||
|
|
||||||
See :pep:`572` for a full description.
|
See :pep:`572` for a full description.
|
||||||
|
|
||||||
(Contributed by Emily Morehouse in :issue:`35224`.)
|
(Contributed by Emily Morehouse in :issue:`35224`.)
|
||||||
|
|
@ -92,20 +127,69 @@ See :pep:`572` for a full description.
|
||||||
Positional-only parameters
|
Positional-only parameters
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
There is new syntax (``/``) to indicate that some function parameters
|
There is a new function parameter syntax ``/`` to indicate that some
|
||||||
must be specified positionally (i.e., cannot be used as keyword
|
function parameters must be specified positionally and cannot be used as
|
||||||
arguments). This is the same notation as shown by ``help()`` for
|
keyword arguments. This is the same notation shown by ``help()`` for C
|
||||||
functions implemented in C (produced by Larry Hastings' "Argument
|
functions annotated with Larry Hastings' `Argument Clinic
|
||||||
Clinic" tool). Example::
|
<https://docs.python.org/3/howto/clinic.html>`_ tool.
|
||||||
|
|
||||||
|
In the following example, parameters *a* and *b* are positional-only,
|
||||||
|
while *c* or *d* can be positional or keyword, and *e* or *f* are
|
||||||
|
required to be keywords::
|
||||||
|
|
||||||
|
def f(a, b, /, c, d, *, e, f):
|
||||||
|
print(a, b, c, d, e, f)
|
||||||
|
|
||||||
|
The following is a valid call::
|
||||||
|
|
||||||
|
f(10, 20, 30, d=40, e=50, f=60)
|
||||||
|
|
||||||
|
However, these are invalid calls::
|
||||||
|
|
||||||
|
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
|
||||||
|
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument
|
||||||
|
|
||||||
|
One use case for this notation is that it allows pure Python functions
|
||||||
|
to fully emulate behaviors of existing C coded functions. For example,
|
||||||
|
the built-in :func:`pow` function does not accept keyword arguments::
|
||||||
|
|
||||||
def pow(x, y, z=None, /):
|
def pow(x, y, z=None, /):
|
||||||
r = x**y
|
"Emulate the built in pow() function"
|
||||||
if z is not None:
|
r = x ** y
|
||||||
r %= z
|
return r if z is None else r%z
|
||||||
return r
|
|
||||||
|
|
||||||
Now ``pow(2, 10)`` and ``pow(2, 10, 17)`` are valid calls, but
|
Another use case is to preclude keyword arguments when the parameter
|
||||||
``pow(x=2, y=10)`` and ``pow(2, 10, z=17)`` are invalid.
|
name is not helpful. For example, the builtin :func:`len` function has
|
||||||
|
the signature ``len(obj, /)``. This precludes awkward calls such as::
|
||||||
|
|
||||||
|
len(obj='hello') # The "obj" keyword argument impairs readability
|
||||||
|
|
||||||
|
A further benefit of marking a parameter as positional-only is that it
|
||||||
|
allows the parameter name to be changed in the future without risk of
|
||||||
|
breaking client code. For example, in the :mod:`statistics` module, the
|
||||||
|
parameter name *dist* may be changed in the future. This was made
|
||||||
|
possible with the following function specification::
|
||||||
|
|
||||||
|
def quantiles(dist, /, *, n=4, method='exclusive')
|
||||||
|
...
|
||||||
|
|
||||||
|
Since the parameters to the left of ``/`` are not exposed as possible
|
||||||
|
keywords, the parameters names remain available for use in ``**kwargs``::
|
||||||
|
|
||||||
|
>>> def f(a, b, /, **kwargs):
|
||||||
|
... print(a, b, kwargs)
|
||||||
|
...
|
||||||
|
>>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways
|
||||||
|
10 20 {'a': 1, 'b': 2, 'c': 3}
|
||||||
|
|
||||||
|
This greatly simplifies the implementation of functions and methods
|
||||||
|
that need to accept arbitrary keyword arguments. For example, here
|
||||||
|
is an except from code in the :mod:`collections` module::
|
||||||
|
|
||||||
|
class Counter(dict):
|
||||||
|
|
||||||
|
def __init__(self, iterable=None, /, **kwds):
|
||||||
|
# Note "iterable" is a possible keyword argument
|
||||||
|
|
||||||
See :pep:`570` for a full description.
|
See :pep:`570` for a full description.
|
||||||
|
|
||||||
|
|
@ -174,17 +258,31 @@ Android and Cygwin, whose cases are handled by the script);
|
||||||
this change is backward incompatible on purpose.
|
this change is backward incompatible on purpose.
|
||||||
(Contributed by Victor Stinner in :issue:`36721`.)
|
(Contributed by Victor Stinner in :issue:`36721`.)
|
||||||
|
|
||||||
f-strings now support = for quick and easy debugging
|
|
||||||
-----------------------------------------------------
|
|
||||||
|
|
||||||
Add ``=`` specifier to f-strings. ``f'{expr=}'`` expands
|
f-strings support ``=`` for self-documenting expressions and debugging
|
||||||
to the text of the expression, an equal sign, then the repr of the
|
----------------------------------------------------------------------
|
||||||
evaluated expression. So::
|
|
||||||
|
|
||||||
x = 3
|
Added an ``=`` specifier to :term:`f-string`\s. An f-string such as
|
||||||
print(f'{x*9 + 15=}')
|
``f'{expr=}'`` will expand to the text of the expression, an equal sign,
|
||||||
|
then the representation of the evaluated expression. For example:
|
||||||
|
|
||||||
Would print ``x*9 + 15=42``.
|
>>> user = 'eric_idle'
|
||||||
|
>>> member_since = date(1975, 7, 31)
|
||||||
|
>>> f'{user=} {member_since=}'
|
||||||
|
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
|
||||||
|
|
||||||
|
The usual :ref:`f-string format specifiers <f-strings>` allow more
|
||||||
|
control over how the result of the expression is displayed::
|
||||||
|
|
||||||
|
>>> delta = date.today() - member_since
|
||||||
|
>>> f'{user=!s} {delta.days=:,d}'
|
||||||
|
'user=eric_idle delta.days=16,075'
|
||||||
|
|
||||||
|
The ``=`` specifier will display the whole expression so that
|
||||||
|
calculations can be shown::
|
||||||
|
|
||||||
|
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
|
||||||
|
theta=30 cos(radians(theta))=0.866
|
||||||
|
|
||||||
(Contributed by Eric V. Smith and Larry Hastings in :issue:`36817`.)
|
(Contributed by Eric V. Smith and Larry Hastings in :issue:`36817`.)
|
||||||
|
|
||||||
|
|
@ -295,7 +393,13 @@ Other Language Changes
|
||||||
or :meth:`~object.__complex__` is not available.
|
or :meth:`~object.__complex__` is not available.
|
||||||
(Contributed by Serhiy Storchaka in :issue:`20092`.)
|
(Contributed by Serhiy Storchaka in :issue:`20092`.)
|
||||||
|
|
||||||
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
|
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`::
|
||||||
|
|
||||||
|
>>> notice = 'Copyright © 2019'
|
||||||
|
>>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})')
|
||||||
|
>>> int(copyright_year_pattern.search(notice).group(1))
|
||||||
|
2019
|
||||||
|
|
||||||
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
||||||
|
|
||||||
* Dict and dictviews are now iterable in reversed insertion order using
|
* Dict and dictviews are now iterable in reversed insertion order using
|
||||||
|
|
@ -343,10 +447,30 @@ Other Language Changes
|
||||||
* Added new ``replace()`` method to the code type (:class:`types.CodeType`).
|
* Added new ``replace()`` method to the code type (:class:`types.CodeType`).
|
||||||
(Contributed by Victor Stinner in :issue:`37032`.)
|
(Contributed by Victor Stinner in :issue:`37032`.)
|
||||||
|
|
||||||
* For integers, the three-argument form of the :func:`pow` function now permits
|
* For integers, the three-argument form of the :func:`pow` function now
|
||||||
the exponent to be negative in the case where the base is relatively prime to
|
permits the exponent to be negative in the case where the base is
|
||||||
the modulus. It then computes a modular inverse to the base when the exponent
|
relatively prime to the modulus. It then computes a modular inverse to
|
||||||
is ``-1``, and a suitable power of that inverse for other negative exponents.
|
the base when the exponent is ``-1``, and a suitable power of that
|
||||||
|
inverse for other negative exponents. For example, to compute the
|
||||||
|
`modular multiplicative inverse
|
||||||
|
<https://en.wikipedia.org/wiki/Modular_multiplicative_inverse>`_ of 38
|
||||||
|
modulo 137, write::
|
||||||
|
|
||||||
|
>>> pow(38, -1, 137)
|
||||||
|
119
|
||||||
|
>>> 119 * 38 % 137
|
||||||
|
1
|
||||||
|
|
||||||
|
Modular inverses arise in the solution of `linear Diophantine
|
||||||
|
equations <https://en.wikipedia.org/wiki/Diophantine_equation>`_.
|
||||||
|
For example, to find integer solutions for ``4258𝑥 + 147𝑦 = 369``,
|
||||||
|
first rewrite as ``4258𝑥 ≡ 369 (mod 147)`` then solve:
|
||||||
|
|
||||||
|
>>> x = 369 * pow(4258, -1, 147) % 147
|
||||||
|
>>> y = (4258 * x - 369) // -147
|
||||||
|
>>> 4258 * x + 147 * y
|
||||||
|
369
|
||||||
|
|
||||||
(Contributed by Mark Dickinson in :issue:`36027`.)
|
(Contributed by Mark Dickinson in :issue:`36027`.)
|
||||||
|
|
||||||
* When dictionary comprehensions are evaluated, the key is now evaluated before
|
* When dictionary comprehensions are evaluated, the key is now evaluated before
|
||||||
|
|
@ -576,7 +700,14 @@ Formerly, it only supported the 2-D case.
|
||||||
|
|
||||||
Added new function, :func:`math.prod`, as analogous function to :func:`sum`
|
Added new function, :func:`math.prod`, as analogous function to :func:`sum`
|
||||||
that returns the product of a 'start' value (default: 1) times an iterable of
|
that returns the product of a 'start' value (default: 1) times an iterable of
|
||||||
numbers. (Contributed by Pablo Galindo in :issue:`35606`)
|
numbers::
|
||||||
|
|
||||||
|
>>> prior = 0.8
|
||||||
|
>>> likelihoods = [0.625, 0.84, 0.30]
|
||||||
|
>>> (link: http://math.prod) math.prod(likelihoods, start=prior)
|
||||||
|
0.126
|
||||||
|
|
||||||
|
(Contributed by Pablo Galindo in :issue:`35606`)
|
||||||
|
|
||||||
Added new function :func:`math.isqrt` for computing integer square roots.
|
Added new function :func:`math.isqrt` for computing integer square roots.
|
||||||
(Contributed by Mark Dickinson in :issue:`36887`.)
|
(Contributed by Mark Dickinson in :issue:`36887`.)
|
||||||
|
|
@ -1357,7 +1488,7 @@ Changes in the Python API
|
||||||
* :func:`shutil.copyfile` default buffer size on Windows was changed from
|
* :func:`shutil.copyfile` default buffer size on Windows was changed from
|
||||||
16 KiB to 1 MiB.
|
16 KiB to 1 MiB.
|
||||||
|
|
||||||
* ``PyGC_Head`` struct is changed completely. All code touched the
|
* The ``PyGC_Head`` struct has changed completely. All code that touched the
|
||||||
struct member should be rewritten. (See :issue:`33597`)
|
struct member should be rewritten. (See :issue:`33597`)
|
||||||
|
|
||||||
* The ``PyInterpreterState`` struct has been moved into the "internal"
|
* The ``PyInterpreterState`` struct has been moved into the "internal"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Beginning edits to Whatsnew 3.8
|
||||||
Loading…
Add table
Add a link
Reference in a new issue