if / elif / else
|
Compile-time DCE on __CHIP__ branches; under stdlib = [...] also sys.implementation / sys.platform / uname() guards (RFC 0007, PyMCU#266) |
while + break / continue
|
|
for i in range(n)
|
Runtime or compile-time bound; range(start, stop, step). The counter is as wide as the bounds need: 8-bit for range(n) with n: uint8, 16-bit for range(300), signed for range(200, -1, -1); a declared type on the loop variable is used as written. A constant range of at most 8 steps unrolls when its body is cheap; an expensive body – a nested loop or a call – lowers to a counter loop instead. A loop variable that must stay a compile-time constant (one fed to a const parameter, say Pin(n, ...)) unrolls regardless of body cost. After the loop the variable holds the last value visited, as in Python |
for x in array / for x in [1, 2, 3]
|
Fixed-size array or constant list literal |
for x in named where named = [...] / (...)
|
List and tuple alike, at any length: up to 8 constant elements the loop unrolls against the literal when the body is cheap, past that – or with an expensive body at any length – the elements go into a fixed array read from flash by a counter loop. The element width comes from the widest element |
for x in ["PD2", "PD3"] / for x in (board.D2, board.D3)
|
A constant list of STRINGS unrolls too, and the loop variable binds as a string constant, so a const parameter receiving it resolves as it would from a literal. Also the pair form, for pin, name in [(board.D2, "D2"), ...] |
for i, x in enumerate(iterable)
|
Compile-time index counter; enumerate(range(...)) with runtime bounds keeps a runtime index. enumerate(s.split(sep)) on compile-time strings unrolls the split chunks, and enumerate(s) over one compile-time string iterates its characters: eight or fewer unroll to compile-time pairs, a longer string runs a counter loop over its flash copy with the character a runtime uint8 ord() accepts (adafruit_framebuf text()) |
for chunk in s.split(sep)
|
Compile-time unroll over a string whose text is known – literal, module constant or parameter bound to one; maxsplit as a compile-time int. A split() call as a value is refused: there is no list to hand back |
for x, y in zip(a, b)
|
Compile-time unroll over paired lists |
reversed(iterable)
|
Compile-time reverse unroll; reversed(range(...)) is the descending range |
match / case
|
Literal, wildcard, OR (|), guard if cond, sequence, capture, dotted-name patterns; DCE on __CHIP__. A capture binds the name the way CPython binds it at that point: the module global at module level, a function-scoped local inside a function, and one slot per expansion inside an @inline |
def
|
Typed params, defaults, keyword args, overloading by type, tuple multi-return (a tuple-returning function force-inlines; annotated -> (T1, T2), -> tuple[T1, T2] or -> Tuple[T1, T2]). A @property that returns a tuple is the same f()[k] site (self.measurements[0]). return struct.unpack_from(fmt, buf, off) delivers the format’s fields as the result tuple, no annotation needed. return (a, b) if c else (a, b, d) is a tuple return too when c folds at compile time, and obj[i] = f() binds those slots as the sequence __setitem__ unpacks (adafruit_neopixel wheel). A return None or bare return on a reached path of a -> X function is refused – None has no width. -> Optional[X] (also `-> X |
Top-level scripts (no def main():) |
Compiler synthesizes main from top-level statements |
Module-level main() (bare, or under if __name__ == "__main__":) |
Says where the entry point’s body runs: what is written after the call runs after the body. A second call, and an early return with module-level code after the call, are refused |
class
|
ZCA @inline flattening, constructors, @property / @name.setter; a class attribute whose class defines __get__/__set__ is a descriptor, and obj is the owning instance even when annotated with a typing-only name (#360, #419); type(inst) in that rewrite is the source class name, including for an imported class; value: Any on __set__ is the written value, not a missing width; value <<= n keeps value so a later read of it is the shifted bits; obj.attr = (a, b) on a descriptor member calls __set__ with the tuple as value, and obj.attr[k] on a tuple-returning __get__ is f()[k] |
Nested class |
Constructible, and its constants readable through both names: Outer.Inner.A, and mod.Outer.Inner.A through the declaring module (busio.UART.Parity.ODD) |
Single-level class inheritance |
ZCA base + derived; super() calls. class C(mod.Base) after import pkg as mod resolves mod.Base to the defining module, so super().__init__ expands the imported constructor. A field assigned inside that base __init__ if (self.format = Fmt()) is still a constructor field (adafruit_ssd1306 / framebuf.FrameBuffer) |
class Foo(Enum)
|
Zero-cost integer constants; no SRAM |
with obj: / with a as x, b as y:
|
__enter__ / __exit__; zero-cost for @inline methods
|
assert condition, msg
|
Compile-time only; statically false → CompileError |
global / nonlocal
|
Cross-function variable access; nonlocal in @inline |
try / except / else / finally, raise, bare raise
|
AVR + ARM (RP2040/RP2350); zero-cost T-flag propagation (AVR: SET/CLT/BRTS; ARM: an internal flag+code global pair — no setjmp/longjmp on either); errors propagate across calls to any depth and are caught at the call site; finally runs on every exit path (caught, propagated, return/break/continue); unhandled raise prints "E:TypeName\r\n" to UART0 then halts, or "E:TypeName: message\r\n" when the raise carried one; except E as e binds a bounded object – print(e), str(e), e.args[0] read the raise’s message (a string literal, or a deferred print of an f-string / concatenation / call, #435) and isinstance(e, X) compares the code, at the cost of one module word and one store per raise, emitted only when some handler in the program binds a name; raise X(...) from Y compiles as raise X(...) (#434) |
except type spellings
|
A bare name, a tuple of names (except (A, B):, #346 — one comparison per alternative into the one handler body), or a module-qualified name (except adafruit_irremote.IRNECRepeatException:) in either position; the qualifier resolves through the import, import mod as x included, to the code the class was scanned under |
Integer arithmetic promotion |
+/-/*/<< promote to the next wider type (uint8 255 + 45 == 300); the annotation is a storage width; uint8(a + b) is the fixed-width escape hatch; out-of-range literals / folded constants are CompileError
|
True division / vs // |
/ yields float (soft-float, warns on integer operands); // / % are integer floor div / mod; runtime divide-by-zero raises ZeroDivisionError
|
f-strings (streamed) |
print(f"..."), uart.write_str/println(f"..."), lcd.print_str(f"...") with runtime interpolations and format specs ({x:02x}, {x:08b}, {x:04d}, {t:.1f}, {v:6.3f}, …); lowered to direct writes, no heap. float interpolations print two rounded decimals; float specs print N decimals with width/zero padding, rounding half-to-even on the exact float32 expansion like CPython
|
print() of a buffer
|
print(bytearray), print(arr[a:b]) and print(obj[a:b]) (via __getitem__/__len__) emit the CPython repr — bytearray(b'\xcc\x10\xca\xfe'); the length must be compile-time
|
print(float)
|
Two rounded decimals, trailing zero trimmed but never past the first: 3.25, -2.25, 0.05, 123.75, 1234.5 |
Functions with > 5 arguments |
Overflow arguments passed via a fixed SRAM spill region |
in / not in
|
Compile-time fold on constant list; runtime equality chain. A call that returns an instance with __contains__ dispatches the dunder ("Linux" not in uname(), #466); two compile-time strings are substring membership ("RP2350" in uname().machine). A name bound to a compile-time string tests a set/list of compile-time strings by text (ORDER in {RGB, GRB}, adafruit_neopixel wheel) |
seq.index(x)
|
On a name bound to a compile-time tuple/list: folds when x folds, else a compare chain over the elements that raises ValueError on a miss (adafruit_tcs34725 _GAINS.index(val)) |
isinstance(x, T)
|
Folds at compile time: a ZCA instance against a class or subclass (#424), or a value against the builtins tuple/list/int from its known shape (#423) – through an inline-parameter alias, a keyword argument, or a module-level string’s own text (adafruit_neopixel pixel_order); isinstance(x, slice) is always False – nothing is a runtime slice (adafruit_pixelbuf __setitem__); a None-bound name answers False to every builtin |
is / is not
|
Maps to == / != |
divmod(a, b)
|
Returns (quotient, remainder) |
bitcast(T, v)
|
Reinterpret raw bytes as T; float↔uint32; compile-time folding |
hex(n) / bin(n) / round(x)
|
Compile-time: hex(255) → "0xff"; round folds a compile-time float/int half-to-even like CPython |
sum(iterable) / any(iterable) / all(iterable)
|
Compile-time fold or unrolled chain |
all/any/sum/min/max(x ... for x in it)
|
A generator expression as the DIRECT argument of a reduction unrolls at compile time over a known-length iterable (tuple/list literal, const sequence, range of constants, compile-time string, fixed-size array). all/any short-circuit like CPython; sum honours start; a for ... if clause filters (adafruit_pixelbuf). Elsewhere a generator expression is refused, naming the five reductions |
Compile-time string methods |
On a name bound to ONE text (literal, module constant, parameter receiving one – through super().__init__ and nested @inline calls, Union[str, ...] parameters included): len(s), s[i], needle in s, s == "lit", s[a:b] slices, str(x) of a constant, s.strip()/lstrip()/rstrip(), s.index()/s.find() (miss: catchable ValueError / -1), s.startswith()/s.endswith(), s.count(), s.replace(), s.upper(), s.lower() all fold |
str(n) compile-time
|
str(42) → "42" string constant
|
A str decided at run time |
A name the branches of an if/else, a loop body, a global rebind or a CONDITIONAL EXPRESSION bind to different texts holds the interned id in one 16-bit slot; print / uart.write_str / println and == / != against a literal dispatch on it, and the texts stay in flash. A conditional expression written straight into a write (print("mono" if k == 0 else "none")) lowers as the condition plus a literal write per arm and needs no slot; a condition that folds picks its arm at compile time (#378) |
pow(x, n) / x ** n / math.pow(x, n)
|
Compile-time integer fold; runtime integer unroll; runtime float via __pymcu_powf (#463) |
math.sqrt/exp/log/radians(x)
|
Software float, run-time argument. sqrt is Newton-Raphson after a scale reduction; log and exp are the two halves of __pymcu_powf’s series; radians is a scaling multiply that folds for a constant angle. Each body lowers LAZILY, so import math with no call costs 0 bytes and a program carries only what it calls. Only these four: each is here because a measured library stops without it (max31865, thermistor, sgp30, mpu6050/lsm6ds). math.pi / math.e are not defined: a module-level float constant in an imported module is storage nothing initialises |
Forward-reference annotation "Name" |
A type named as a string literal (PEP 484), the spelling every Adafruit driver uses for its own __enter__ return. The quotes come off and the name inside is resolved and checked like any other, in AnnotationText so both front ends read it the same way |
bytes literal b"\x00\xFF"
|
Treated as uint8[N]; works in for, array init, len() |
bytearray
|
Mutable SRAM buffer. A function that fills one and returns it is expanded at the call site so the caller indexes the same storage (#464). memoryview is a CPython builtin type this compiler stores, so -> memoryview is the same view memoryview() already wraps. Replaying name = bytearray(n) does not undo a .extend() that already grew it, so a class-body _fit(2) keeps a 3-byte _BUFFER |
bytes([...]) / bytes(N) as a call argument
|
Written inline at a call site: unrolls into an @inline callee’s unannotated buffer parameter the same way a list literal does, or lays out a hidden fixed buffer for a bytearray/bytes-annotated parameter of a real function. bytes(n) with a run-time n is refused (bytearray(n) takes one) |
Union[A, B] on an @inline/constructor parameter
|
Read as the argument’s type AT THAT CALL SITE, which must be one of the members – the same way an @inline overload dispatches. A field assigned from it takes the site’s type. List[X]/Tuple[X, ...] matches a fixed array/list literal; Callable[...] matches a function reference. A Protocol member is structural (#465): a class that has the protocol’s members matches even when it is not named as the protocol. A non-matching argument is refused, naming the members. A real subroutine’s parameter, or any non-parameter position, keeps the union refusal |
Annotation alias Name = Union[...] |
ColorUnion = Union[int, uint8] binds the alias at compile time – including inside a discarded if TYPE_CHECKING: / compat-layer guard – and x: ColorUnion resolves it to the same members as the spelled-out union (adafruit_pixelbuf)
|
input(prompt?, maxlen?)
|
line: bytearray = input("prompt") — reads newline-terminated line from UART; auto-injects UART init preamble
|
open(name, mode)
|
RFC 0008 romfs — resolves at compile time to a handle over a flash blob (no filesystem on the chip). name/mode are compile-time strings; read modes only. read(n) (compile-time n, yields a flash view fusing with [i]/len()/struct.unpack), readinto, readline(max), seek, tell, close, with. Driver embeds via [tool.pymcu] files = [...] or auto-embeds a literal-opened file in the sources |
int.from_bytes(b, 'little'/'big')
|
Compile-time fold or runtime |
Raw strings r"\n" |
No escape processing |
Extended unpacking first, *rest = tup |
Compile-time tuples only (PEP 3132) |
Nested list comprehensions |
Full outer × inner product unroll; if filter supported |
for v in [Cls(p) for p in (...)]
|
CT unroll of ZCA instance arrays from list comprehensions; plain for-in and enumerate both supported. An element built by a factory call keeps its returned class ([pcf.get_pin(i) for i in range(8)], adafruit_pcf8574) |
A list given to a class (Bar([Pin(a), Pin(b)]), Bar(pins)) |
Compile-time sequence bound to the parameter and to the self field: constant subscript, for, len(), and a run-time subscript that calls a method (up to 8 elements, lowered as a selection) |
A list of numbers or a bytearray given to a class |
The field is another name for the values or the buffer: constant subscript and for on the values, run-time indexed load and store on the buffer |
str.join
|
sep.join([...]) folds compile-time strings, in expression position too (print(sep.join([a, b]))); ''.join([chr(b) for b in buf]) lowers to a runtime string (the MicroPython/CircuitPython bytes-to-string idiom); sep.join(f"{x:02x}" for x in buf) – a generator/comprehension over a compile-time sequence producing f-strings, compile-time strings or chr(b) – streams in print/uart.write_str/println and materializes into a fixed buffer (a runtime string, like an f-string-as-value) elsewhere
|
Slice indexing arr[1:3], arr[::2] |
READ needs compile-time constant bounds (folding through function-local constants too) and yields a fixed-size array; a slice of SRAM-backed storage marshals to a bytearray parameter by base address. Equal-length slice ASSIGNMENT (arr[a:b] = src) with list/bytes/array/slice sources, incl. overlapping same-array copies (snapshot semantics), through __setitem__ objects (nvm[0:4] = b'...'), a module bytearray, an instance-member buffer (self.buf), and a run-time start whose length is compile-time (buf[i:i+n] = bytes(fill)). ITERATION accepts runtime bounds (for b in buf[0:n]); a runtime step is a diagnostic |
lambda x: expr (no capture)
|
Inlined as anonymous @inline function |
Dunder operator overloading |
__add__, __sub__, __mul__, __len__, __contains__, __getitem__, __setitem__, comparisons, bitwise. Dispatched wherever the operator is written: as a condition, as a value, at module level, and on a class-typed field receiver
|
Comparing two instances with no comparison dunder |
== / != / is / is not fall back to identity, as CPython does; an ordering is refused, and so are max() / min() over instances
|
__new__, __init_subclass__, __del__
|
The two construction hooks are refused where they are written; a destructor compiles, never runs, and is warned about |
@extern("symbol")
|
External C/C++ symbol interop with AVR ABI |
__name__ / if __name__ == "__main__":
|
Compile-time guard; body promoted in main, eliminated in libs |
Triple-quoted strings """...""" / '''...''' |
Multiline string literals; leading newline after opening quote stripped; useful for multiline asm() |
list[T] heap-allocated list
|
x: list[uint8] = list() / list(N) / [a, b, c]; append(), len(), x[i], for v in x:; bounded bump allocator + GC; suitable for ATmega328P (2 KB SRAM) and larger. A list[T] parameter or return also works on a real (non-@inline) function, expanded at each call site
|
import os / os.uname()
|
Compile-time five-field record of __CHIP__ (sysname "PyMCU", machine the chip, with an RP2040/RP2350 token on those parts). "Linux" not in uname() and "RP2350" in uname().machine fold. os.name is "posix", os.sep is "/". stat(name) / listdir(dir) answer from the embedded-file table (RFC 0008) — stat returns the ten-field tuple (size at index 6), listdir unrolls the names under the prefix, sorted; getenv is not defined (#466) |
Unannotated field first store |
A string literal or bytearray(...) / bytes(...) is that kind, not uint8. self._message = "" then a str setter and self._gpio = bytearray(n) then a buffer setter are the same field; an int then a str is still refused |
Constant tuple field |
self.scale = (524288, ...) is the same fixed array as self.buf = [0, 0, 0]. Counted as a scalar the class became one-field and self.scale[n] was a bit index (adafruit_dps310)
|
str parameter text
|
A compile-time string of any length bound to a str parameter keeps its text, so struct.calcsize(fmt) folds (StructArray(0x06, "<HH", 16) in adafruit_pca9685) |
[None] * n
|
A repeated list of None (or a constant) is a fixed SRAM array. coeffs = [None] * 18 and self.ch = [None] * len(self) are indexable; None is a 0 slot (adafruit_dps310, adafruit_pca9685) |
2-D grid [[v] * W for _ in range(H)] |
One flat T[W*H] array – g[y][x] is g[y*W+x] with the same index code the hand-flattened spelling emits. Also [bytearray(W) for _ in range(H)] and self.g = <same> in __init__; both dimensions fold like a fixed array’s size (literal, const name, module constant, or a constructor argument literal at every call site). len(g) is H, len(g[y]) is W, for row in g is a row-index loop, for x in g[y] iterates a row, r = g[y] binds a row view usable only for r[x]/len(r)/for x in r in the same block. A row is a view, not a value: passing, returning, storing, comparing, in, slicing or appending it, rebinding g[y], and g[a:b] are all refused; [[0]*W] * H is refused because CPython’s spelling aliases one row |
x = a, b, c
|
An unparenthesized comma RHS is a tuple, the same wrap return a, b already had. fill = (color >> 16) & 255, (color >> 8) & 255, color & 255 (adafruit_framebuf) |
return a, (b, c, d), e
|
A tuple-return element that is itself a fixed literal sequence reaches the caller as a compile-time sequence, not a runtime tuple: bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(...) unpacks (r, g, b) so byteorder_tuple[i] folds and if dotstar_mode: drops its branch (adafruit_pixelbuf) |
buf[i:i+n] = bytes(fill)
|
Equal-length slice assign onto a bytearray (and onto self.buf), with a run-time start whose length is compile-time (i:i+3) and bytes(named_seq) as the source (adafruit_framebuf RGB888 fill) |
"mod.Cls" annotation
|
A quoted dotted class is the same type as unquoted mod.Cls. "Vec" already was the bare name (#261); "adafruit_si7021.SI7021" is the dotted spelling (adafruit_si7021) |
word[i], crc[i] = unpack(...)
|
An IndexExpr unpack binds the RHS to a name then stores t[k]. A struct.unpack buffer slice may start at a run-time offset (data[i*6:(i*6)+6]) (adafruit_sht31d) |
@classmethod
|
Compile-time class-namespace population: cls is the receiver class. setattr(cls, name, value), cls.attr = {} and cls.attr[k] = v fill that class; return cls() constructs it (adafruit_sht4x / tmp117 CV.add_values) |
self.prop[k] on a tuple @property
|
A getter that returns a tuple is f()[k]. return self.measurements[0] from temperature is the first slot (adafruit_sht4x) |
self.buf[a:b]
|
A field bytearray slices the same way a named buf[a:b] does. temp_data = self._buffer[0:2] (adafruit_sht4x) |
class C(mod.Base) + super()
|
An imported dotted base unwraps the module alias. import adafruit_framebuf as framebuf then class _SSD1306(framebuf.FrameBuffer) expands super().__init__ (adafruit_ssd1306) |
self.x = ... inside a base __init__ if
|
A super-expanded base constructor is still __init__. self.format = MVLSBFormat() in FrameBuffer.__init__ is a constructor field, not a missing field of the subclass (adafruit_ssd1306) |
super().__init__(reset=None)
|
A None argument through super() is still None. if self.reset_pin: folds and the guarded DigitalInOut use is not lowered (adafruit_ssd1306) |
for x in (NAME, a if c else b, self.n - 1)
|
A for-in tuple element folds like any other constant: a const name, a field ternary, a comparison ternary, or field arithmetic (adafruit_ssd1306 init_display) |
Parameter shadows import ... as |
A parameter of the same name as an import alias is the parameter. def set_pixel(framebuf, ...): framebuf.stride after import adafruit_framebuf as framebuf is the instance field. A class-body function with no self that reads a parameter field expands at the call site so that class is visible (adafruit_ssd1306 MVLSBFormat.set_pixel) |
Field array list comprehension |
obj.buf = [x for i in range(len(obj.buf))] fills the field array already bound. A list comprehension as a value is still refused (adafruit GS2HMSBFormat.fill)
|
if buf_format == MVLSB in __init__
|
When the constructor is expanded with a bound constant, only that format class is assigned. A local that holds that constant (_FRAMEBUF_FORMAT = MVLSB) forwarded through super().__init__ is still a constant, so the I2C subclass keeps MVLSBFormat. A no-self method that forwards the buffer to a sibling (GS2HMSBFormat.rect -> set_pixel(framebuf, ...)) expands at the call site so an unused format class is not compiled (adafruit_framebuf) |
memoryview(buf)[k:] as a value
|
A writable window of buf (offset + shorter len), not a copy. super().__init__(memoryview(self.buffer)[1:]) then a second hop super().__init__(buffer, ...) keeps the window, so len(framebuf.buf) / framebuf.buf[i] = fill writes buffer[1:] and leaves the I2C command byte. A plain buf[a:b] is still a copy (adafruit_ssd1306 / sht4x) |
TYPE_CHECKING inner except NotImplementedError |
The try body’s import stays in scope. from pwmio import PWMOut is not dropped, and the stub handler is not loaded (#480, #481) |
for p in (inst, inst)
|
A tuple or list of already-constructed ZCA instances unrolls the same way for p in self._pins does. pin.direction = OUTPUT through the loop variable is the @property setter (adafruit_character_lcd) |
bytearray(self.field)
|
A field that holds a compile-time integer is a compile-time size (adafruit_74hc595’s self._gpio = bytearray(self._number_of_shift_registers)) |
Local class vs imported name |
A class defined in a module shadows an import of the same name from another module. DigitalInOut(pin, self) in adafruit_74hc595 is that file’s two-argument class, even when main imported digitalio.DigitalInOut |
Constructor not outlined |
__init__ is expanded at each construction. A class-typed parameter is the argument’s class, not the annotation (Lcd(mcp.get_pin(1), ...) annotated digitalio.DigitalInOut is still the expander pin). A plain function whose body returns a construction (def I2C(): return _board_i2c(SCL, SDA), the generated board.py) expands the same way a declared -> busio.I2C factory does, so i2c = board.I2C() then b.try_lock() on b: busio.I2C resolves to the class, not the receiver’s name
|
Rebound module alias |
from adafruit_motor import servo then servo = servo.Servo(pwm) rebinds the name; later reads and calls see the instance, not the module (#467)
|
time.struct_time
|
Stdlib stub with the nine CPython field names, so Adafruit RTC from time import struct_time in a typing try does not fail |
collections.namedtuple
|
Compile-time class factory: Name = namedtuple("Name", ("a", "b")) becomes a ZCA class with those fields, __len__ and __match_args__. The bound name is the class (adafruit_irremote’s IRMessage) |
Arena allocator for runtime-sized bytearray(n) |
Allocates from a static arena (no free()) wherever the compiler can prove the statement runs at most once (a module-level statement not in a loop, or an @inline __init__ reached only through inlining from one); refused elsewhere, naming the reason. x[i], x[i] = v, len(x), both as a local and as an @inline __init__’s field, through further @inline method calls; for b in x iterates the bytes when the buffer reaches the loop through an @inline parameter binding or a field (self._post_brightness_buffer into neopixel_write); new MemoryError on overflow; pymcu build reports the reservation. AVR only. See docs/rfcs/0004-arena-allocator.md |
Closed dict / set literals |
d = {0: 10, "mid": 2} / OK = {1, 3, 5} bind compile-time lookup tables with no storage: d[const] folds, d[runtime] compare-chains and raises KeyError, x in d and len(d) fold. A class-body dict (self.gain_values[gain]) is the same table, including mixed int/float values. Read-only
|
pymcu.collections.FixedDict
|
Mutable fixed-capacity integer dict — open addressing over per-instance fixed arrays, no heap and no GC |
f-string as a value |
s = f"t={t} C" builds into a compiler-managed fixed bytearray; len(s), s[i] (the one-character string at that position, so print(s[i]) writes the character), print(s), buffer reuse on re-assignment. Float format specs ({v:.2f}) work here too, and an int spec ({v:X}, {v:04d}, {v:b}, {v:o}) folds to its text wherever the whole f-string is a compile-time constant
|
async def / await, generators (yield)
|
Lowered to a zero-cost state-machine class with poll(); await asyncio.sleep/sleep_ms anywhere in the body; executors asyncio.run / asyncio.gather; for x in gen(...) desugars to a poll loop. yield from delegates, and a generator method works through a bound receiver |
Type inference for unannotated def params/returns |
Outlined functions join call-site evidence, defaults and return expressions (safe integer widening) instead of defaulting to uint8; class methods join the return side, so self.x = self._m() reads _m’s inferred return type as field-width evidence (#489) |
Value-returning methods on nested ZCA fields |
self.pin.read() on a class-typed field dispatches through facade re-exports and single-level inheritance — the shape the compat layers are built on
|
def f(): return C(...) returning a multi-field ZCA
|
A plain function whose return is a ZCA construction force-inlines at the call site, the same rule as a ZCA-typed parameter: board.I2C() -> _board_i2c(SCL, SDA) keeps every field store the constructor emits (adafruit_ssd1306). A single-field class still returns its register-packed handle; a declared -> C still lowers sret |
f"..." "literal" implicit concatenation
|
An f-string adjacent to plain literals folds into one JoinedStr, the same merge CPython’s parser makes — the spelling of adafruit_seesaw’s chip-id raise; as a deferred raise message the merged parts replay like print |
buf += src on a fixed bytearray
|
In-place concat: the buffer’s compile-time size grows by the source’s length and the source bytes store into the new tail (full_buffer += buf in adafruit_seesaw.write). The += must sit in the same run-time branch context as the buffer’s declaration; anything else is refused, naming why |
buf[a:] = src open-ended slice assign
|
An open-ended slice takes its length from the source’s compile-time length; the start may be run-time (cmd[offset:] = struct.pack(">I", pins) in adafruit_seesaw) |
struct.pack(fmt, v...) as a value
|
name = struct.pack(fmt, v...) binds a fixed bytearray of calcsize bytes — pack_into’s writes onto a fresh name — and works as a slice-assign source. struct covers the 4-byte codes I/i/L/l under </>/!
|
try/except ImportError in a function-scope-imported module
|
A module discovered through an import inside a function body gets the same optional-import marking the dependency graph applies at top level, so adafruit_seesaw’s micropython.const pinmap idiom folds instead of failing on the stub handler |