From 9ab66b50cb0f15dab9c935324751edb638144099 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Apr 2022 23:40:42 +1000 Subject: [PATCH] docs/reference: Update constrained docs now that tuples can be const. Signed-off-by: Damien George --- docs/reference/constrained.rst | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index 816a20f9d..8d3ba0e3a 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -126,8 +126,9 @@ that the objects remain in flash memory rather than being copied to RAM. The Python built-in types. When considering the implications of frozen bytecode, note that in Python -strings, floats, bytes, integers and complex numbers are immutable. Accordingly -these will be frozen into flash. Thus, in the line +strings, floats, bytes, integers, complex numbers and tuples are immutable. +Accordingly these will be frozen into flash (for tuples, only if all their +elements are immutable). Thus, in the line .. code:: @@ -146,16 +147,16 @@ As in the string example, at runtime a reference to the arbitrarily large integer is assigned to the variable ``bar``. That reference occupies a single machine word. -It might be expected that tuples of integers could be employed for the purpose -of storing constant data with minimal RAM use. With the current compiler this -is ineffective (the code works, but RAM is not saved). +Tuples of constant objects are themselves constant. Such constant tuples are +optimised by the compiler so they do not need to be created at runtime each time +they are used. For example: .. code:: - foo = (1, 2, 3, 4, 5, 6, 100000) + foo = (1, 2, 3, 4, 5, 6, 100000, ("string", b"bytes", False, True)) -At runtime the tuple will be located in RAM. This may be subject to future -improvement. +This entire tuple will exist as a single object (potentially in flash if the +code is frozen) and referenced each time it is needed. **Needless object creation** @@ -214,7 +215,7 @@ buffer; this is both faster and more efficient in terms of memory fragmentation. **Bytes are smaller than ints** -On most platforms an integer consumes four bytes. Consider the two calls to the +On most platforms an integer consumes four bytes. Consider the three calls to the function ``foo()``: .. code:: @@ -222,12 +223,16 @@ function ``foo()``: def foo(bar): for x in bar: print(x) + foo([1, 2, 0xff]) foo((1, 2, 0xff)) foo(b'\1\2\xff') -In the first call a tuple of integers is created in RAM. The second efficiently +In the first call a `list` of integers is created in RAM each time the code is +executed. The second call creates a constant `tuple` object (a `tuple` containing +only constant objects) as part of the compilation phase, so it is only created +once and is more efficient than the `list`. The third call efficiently creates a `bytes` object consuming the minimum amount of RAM. If the module -were frozen as bytecode, the `bytes` object would reside in flash. +were frozen as bytecode, both the `tuple` and `bytes` object would reside in flash. **Strings Versus Bytes**