← index #7899Issue #4899
Related · high · value 2.111
QUERY · ISSUE

Discussion of Python 3.8 support

openby mattytrentiniopened 2021-10-14updated 2025-10-03
py-core

This issue is intended to track the status of Python 3.8 core features as implemented by MicroPython.

Python 3.8.0 (final) was released on the 14 October 2019. The Features for 3.8 are defined in PEP 569 and a detailed description of the changes can be found in What's New in Python 3.8.

  • PEP 570, Positional-only arguments
  • PEP 572, Assignment Expressions; Done, see #4908
  • PEP 574, Pickle protocol 5 with out-of-band data
  • PEP 578, Runtime audit hooks
  • PEP 587, Python Initialization Configuration
  • PEP 590, Vectorcall: a fast calling protocol for CPython

Misc

  • f-strings support = for self-documenting expressions and debugging; Done, see #7649

Other language changes

  • A continue statement was illegal in the finally clause due to a problem with the implementation. In Python 3.8 this restriction was lifted; Done, see 82c494a97e874912e7eb23d2f03f39212e343fb3
  • The bool, int, and fractions.Fraction types now have an as_integer_ratio() method like that found in float and decimal.Decimal
  • Constructors of int, float and complex will now use the __index__() special method, if available and the corresponding method __int__(), __float__() or __complex__() is not available
  • Added support of \N{name} escapes in regular expressions
  • Dict and dictviews are now iterable in reversed insertion order using reversed()
  • The syntax allowed for keyword names in function calls was further restricted. In particular, f((keyword)=arg) is no longer allowed
  • Generalized iterable unpacking in yield and return statements no longer requires enclosing parentheses
  • When a comma is missed in code such as [(10, 20) (30, 40)], the compiler displays a SyntaxWarning with a helpful suggestion
  • Arithmetic operations between subclasses of datetime.date or datetime.datetime and datetime.timedelta objects now return an instance of the subclass, rather than the base class
  • When the Python interpreter is interrupted by Ctrl-C (SIGINT) and the resulting KeyboardInterrupt exception is not caught, the Python process now exits via a SIGINT signal or with the correct exit code such that the calling process can detect that it died due to a Ctrl-C
  • Some advanced styles of programming require updating the types.CodeType object for an existing function
  • For integers, the three-argument form of the pow() function now permits the exponent to be negative in the case where the base is relatively prime to the modulus
  • Dict comprehensions have been synced-up with dict literals so that the key is computed first and the value second
  • The object.__reduce__() method can now return a tuple from two to six elements long

Changes to MicroPython built-in modules

  • asyncio
    • asyncio.run() has graduated from the provisional to stable API
    • Running python -m asyncio launches a natively async REPL
    • The exception asyncio.CancelledError now inherits from BaseException rather than Exception and no longer inherits from concurrent.futures.CancelledError
    • Added asyncio.Task.get_coro() for getting the wrapped coroutine within an asyncio.Task
    • Asyncio tasks can now be named, either by passing the name keyword argument to asyncio.create_task() or the create_task() event loop method, or by calling the set_name() method on the task object
    • Added support for Happy Eyeballs to asyncio.loop.create_connection(). To specify the behavior, two new parameters have been added: happy_eyeballs_delay and interleave.
  • gc - get_objects() can now receive an optional generation parameter indicating a generation to get objects from
    • (Note, though, that while gc is a built-in, get_objects() is not implemented for MicroPython)
  • math
    • Added new function math.dist() for computing Euclidean distance between two points
    • Expanded the math.hypot() function to handle multiple dimensions
    • Added new function, math.prod(), as analogous function to sum() that returns the product of a ‘start’ value (default: 1) times an iterable of numbers
    • Added two new combinatoric functions math.perm() and math.comb()
    • Added a new function math.isqrt() for computing accurate integer square roots without conversion to floating point
    • The function math.factorial() no longer accepts arguments that are not int-like
  • sys - Add new sys.unraisablehook() function which can be overridden to control how “unraisable exceptions” are handled

(Changes to non-built-in modules will need to be documented elsewhere.)

CANDIDATE · ISSUE

Support for PEP 572 Assignment Expression

closedby nickovsopened 2019-07-06updated 2020-06-10
py-core

I realise that the current MicroPython doesn't yet fully support all of Python 3.5, let alone 3.6 or 3.7, but since 3.8 is going into beta release I'd like to make a plea for the addition of a very useful and powerful Python 3.8 feature: Assignment Expressions.

Regular variable assignment in Python is a statement, not an expression. While this is fine in most cases there are many common cases where it would be extremely valuable to be able to both store the value of an expression in a variable and make use of that value in another expression. PEP 572 lays out the case for doing this in general. I would like to make the case for why this would be particularly useful in MicroPython.

MicroPython (in my mind at least) is all about being able to run Python in environments that are limited in both memory and CPU power. As a result MicroPython needs to (a) be as efficient as possible and (b) allow the user to be as efficient as possible. More compact code that repeats itself less in both text and action can help a lot, and that is exactly the goal of assignment expressions.

Consider the common scenario in MicroPython where one has a gadget with some registers that include flags and data; you need to check some flags and if they are in some condition you need to perform some processing on the values. Right now you might write:

reg1 = thing.get_reg(1)
if reg1 & R1_READY:
    reg2 = thing.get_reg(2)
    if reg2 & R2_OTHER:
        something_useful(reg1, reg2)

By using assignment expressions this becomes:

if (reg1 := thing.get_reg(1)) & R1_READY and (reg2 := thing.get_reg(2)) & R2_OTHER:
    something_useful(reg1, reg2)

Another scenario that's not uncommon in MicrpPython systems is looping to receive some data and quitting when some sentinel value arrives. Right now you need to do this:

while True:
    line = port.get_line()
    if line == "QUIT":
        break
    process_input(line)

With assignment expressions this becomes much more compact and readable:

while (line := port.get_line()) != "QUIT":
    process_input(line)

Another case where assignment expressions are valuable is as a "witness" inside a loop or comprehension. Have you ever got a False result from calling all() and wondered which one wasn't true? Now you can know:

if all((nonblank := line).strip() == '' for line in lines):
    print("All lines are blank")
else:
    print("First non-blank line:", nonblank)

Capturing processed values in a list comprehension also benefits from avoiding doing processing twice. Right now you have a couple of options:

# Inefficient...
[i.cleaned() for i in stuff if i.cleaned() != '']
# or complex and opaque
[clean for clean in (i.cleaned() for i in stuff) if clean != '']

Now we can write:

[clean for i in stuff if (clean := i.cleaned()) != '']

As a result of all these I think that the benefits of assignment expressions would be particularly useful to Micropython.

Of course all of the usual arguments for not implementing a feature hold just as well for assignment expressions. There will be extra code in the ROM for the parser and byte code generator and there may be some complexity in handling the exceptional cases. That said, I think that there is plenty of scope for this reducing the size of the Python code written by the user and likely for smaller byte code for those cases too.

Probably the most compelling argument against this right now is that this is a Python 3.8 feature code, so updated code won't work on most desktop or server Python deployments just yet. This is probably an argument for this not being a high priority for the time being, but not against feature itself.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied