-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Description
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.