# Core language

Generated Wed 19 Jul 2023 21:24:18 UTC

## f-strings don’t support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings

Cause: MicroPython is optimised for code space.

Workaround: Use the + operator between literal strings when either or both are f-strings

Sample code:

    x, y = 1, 2
    print("aa" f"{x}")  # works
    print(f"{x}" "ab")  # works
    print("a{}a" f"{x}")  # fails
    print(f"{x}" "a{}b")  # fails
    print(f"{x}" f"{y}")  # fails

CPy output: | uPy output:
    aa1
    1ab
    a{}a1
    1a{}b
    12
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets

Cause: MicroPython is optimised for code space.

Workaround: Always use balanced braces and brackets in expressions inside f-strings

Sample code:

    print(f'{"hello { world"}')
    print(f'{"hello ] world"}')

CPy output: | uPy output:
    hello { world
    hello ] world
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Raw f-strings are not supported

Cause: MicroPython is optimised for code space.

Sample code:

    rf"hello"

CPy output: | uPy output:
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## f-strings don’t support the !r, !s, and !a conversions

Cause: MicroPython is optimised for code space.

Workaround: Use repr(), str(), and ascii() explictly.

Sample code:

    class X:
        def __repr__(self):
            return "repr"

        def __str__(self):
            return "str"

    print(f"{X()!r}")
    print(f"{X()!s}")

CPy output: | uPy output:
    repr
    str
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

### Classes

## Special method __del__ not implemented for user-defined classes

Sample code:

    import gc

    class Foo:
        def __del__(self):
            print("__del__")

    f = Foo()
    del f

    gc.collect()

CPy output: | uPy output:
    __del__
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Method Resolution Order (MRO) is not compliant with CPython

Cause: Depth first non-exhaustive method resolution order

Workaround: Avoid complex class hierarchies with multiple inheritance and complex method overrides. Keep in mind that many languages don’t support multiple inheritance at all.

Sample code:

    class Foo:
        def __str__(self):
            return "Foo"

    class C(tuple, Foo):
        pass

    t = C((1, 2, 3))
    print(t)

CPy output: | uPy output:
    Foo
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## When inheriting from multiple classes super() only calls one class

Cause: See Method Resolution Order (MRO) is not compliant with CPython

Workaround: See Method Resolution Order (MRO) is not compliant with CPython

Sample code:

    class A:
        def __init__(self):
            print("A.__init__")

    class B(A):
        def __init__(self):
            print("B.__init__")
            super().__init__()

    class C(A):
        def __init__(self):
            print("C.__init__")
            super().__init__()

    class D(B, C):
        def __init__(self):
            print("D.__init__")
            super().__init__()

    D()

CPy output: | uPy output:
    D.__init__
    B.__init__
    C.__init__
    A.__init__
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Calling super() getter property in subclass will return a property object, not the value

Sample code:

    class A:
        @property
        def p(self):
            return {"a": 10}

    class AA(A):
        @property
        def p(self):
            return super().p

    a = AA()
    print(a.p)

CPy output: | uPy output:
    {'a': 10}
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

### Functions

## Error messages for methods may display unexpected argument counts

Cause: MicroPython counts “self” as an argument.

Workaround: Interpret error messages with the information above in mind.

Sample code:

    try:
        [].append()
    except Exception as e:
        print(e)

CPy output: | uPy output:
    append() takes exactly one argument (0 given)
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Function objects do not have the `__module__` attribute

Cause: MicroPython is optimized for reduced code size and RAM usage.

Workaround: Use `sys.modules[function.__globals__['__name__']]` for non-builtin modules.

Sample code:

    def f():
        pass

    print(f.__module__)

CPy output: | uPy output:
    __main__
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## User-defined attributes for functions are not supported

Cause: MicroPython is highly optimized for memory usage.

Workaround: Use external dictionary, e.g. `FUNC_X[f] = 0`.

Sample code:

    def f():
        pass

    f.x = 0
    print(f.x)

CPy output: | uPy output:
    0
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

### Generator

## Context manager __exit__() not called in a generator which does not run to completion

Sample code:

    class foo(object):
        def __enter__(self):
            print("Enter")

        def __exit__(self, *args):
            print("Exit")

    def bar(x):
        with foo():
            while True:
                x += 1
                yield x

    def func():
        g = bar(0)
        for _ in range(3):
            print(next(g))

    func()

CPy output: | uPy output:
    Enter
    1
    2
    3
    Exit
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

### Runtime

## Local variables aren’t included in locals() result

Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name.

Sample code:

    def test():
        val = 2
        print(locals())

    test()

CPy output: | uPy output:
    {'val': 2}
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Code running in eval() function doesn’t have access to local variables

Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name. Effectively, `eval(expr)` in MicroPython is equivalent to `eval(expr, globals(), globals())`.

Sample code:

    val = 1

    def test():
        val = 2
        print(val)
        eval("print(val)")

    test()

CPy output: | uPy output:
    2
    2
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

### import

## __all__ is unsupported in __init__.py in MicroPython.

Cause: Not implemented.

Workaround: Manually import the sub-modules directly in __init__.py using `from . import foo, bar`.

Sample code:

    from modules3 import *

    foo.hello()

CPy output: | uPy output:
    hello
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## __path__ attribute of a package has a different type (single string instead of list of strings) in MicroPython

Cause: MicroPython does’t support namespace packages split across filesystem. Beyond that, MicroPython’s import system is highly optimized for minimal memory usage.

Workaround: Details of import handling is inherently implementation dependent. Don’t rely on such details in portable applications.

Sample code:

    import modules

    print(modules.__path__)

CPy output: | uPy output:
    ['/github/workspace/micropython/tests/cpydiff/modules']
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## Failed to load modules are still registered as loaded

Cause: To make module handling more efficient, it’s not wrapped with exception handling.

Workaround: Test modules before production use; during development, use `del sys.modules["name"]`, or just soft or hard reset the board.

Sample code:

    import sys

    try:
        from modules import foo
    except NameError as e:
        print(e)
    try:
        from modules import foo

        print("Should not get here")
    except NameError as e:
        print(e)

CPy output: | uPy output:
    foo
    name 'xxx' is not defined
    foo
    name 'xxx' is not defined
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

## MicroPython does’t support namespace packages split across filesystem.

Cause: MicroPython’s import system is highly optimized for simplicity, minimal memory usage, and minimal filesystem search overhead.

Workaround: Don’t install modules belonging to the same namespace package in different directories. For MicroPython, it’s recommended to have at most 3-component module search paths: for your current application, per-user (writable), system-wide (non-writable).

Sample code:

    import sys

    sys.path.append(sys.path[1] + "/modules")
    sys.path.append(sys.path[1] + "/modules2")

    import subpkg.foo
    import subpkg.bar

    print("Two modules of a split namespace package imported")

CPy output: | uPy output:
    Two modules of a split namespace package imported
    /bin/sh: 1: ../ports/unix/build-standard/micropython: not found

Language and External Links

Language
  English
  中文

External links
  openmv.io
  forums.openmv.io
  github.com/openmv/openmv
  micropython.org
  forum.micropython.org
  github.com/micropython/micropython