Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions mypyc/doc/differences_from_python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,28 +237,56 @@ nested function calls, typically due to out-of-control recursion.
Final values
------------

Compiled code replaces a reference to an attribute declared ``Final`` with
the value of the attribute computed at compile time. This is an example of
:ref:`early binding <early-binding>`. Example::
Mypy treats variables and attributes defined as ``Final`` specially.
For instance attributes of native classes, mypyc prevents reassignment
of these attributes.

Mypyc replaces references to a variable or attribute declared ``Final``
with the value of the attribute computed at compile time, when it can
be determined during compilation. Example::

MAX: Final = 100

def limit_to_max(x: int) -> int:
if x > MAX:
return MAX
return x
if x > MAX:
return MAX
return x

The two references to ``MAX`` don't involve any module namespace lookups,
and are equivalent to this code::

def limit_to_max(x: int) -> int:
if x > 100:
return 100
return x
if x > 100:
return 100
return x

When run as interpreted, the first example will execute slower due to
the extra namespace lookups. In interpreted code final attributes can
also be modified.
the extra namespace lookups.

For a final class attribute or global variable whose value can't be
determined during compilation, mypyc defines a hidden native variable
that stores the value when the initialization assignment is evaluated.
Redefining the attribute using ``setattr`` or direct namespace access
has no effect for mypyc-compiled code (in the same compilation unit).

Final global variables and class attributes are faster to read in
compiled code, since they don't have to be looked up from a namespace
dictionary. Thus using a ``Final`` object that holds mutable state in an
attribute tends to be faster than a plain global variable in compiled code::

class Counter:
def __init__(self) -> None:
self.value = 0

x: Final = Counter()
y = 0

def inc() -> None:
# Faster: no Python namespace lookup
x.value += 1
# Slower: access through globals() namespace dictionary
global y
y += 1

.. _free-threading:

Expand Down
Loading