Skip to content

[mypyc] Improve documentation of native and non-native classes #19154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 27, 2025
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
82 changes: 74 additions & 8 deletions mypyc/doc/native_classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ can be assigned to (similar to using ``__slots__``)::
Inheritance
-----------

Only single inheritance is supported (except for :ref:`traits
<trait-types>`). Most non-native classes can't be used as base
classes.
Only single inheritance is supported from native classes (except for
:ref:`traits <trait-types>`). Most non-native extension classes can't
be used as base classes, but regular Python classes can be used as
base classes unless they use unsupported metaclasses (see below for
more about this).

These non-native classes can be used as base classes of native
These non-native extension classes can be used as base classes of native
classes:

* ``object``
Expand All @@ -63,8 +65,6 @@ classes:
* ``IndexError``
* ``LookupError``
* ``UserWarning``
* ``typing.NamedTuple``
* ``enum.Enum``

By default, a non-native class can't inherit a native class, and you
can't inherit from a native class outside the compilation unit that
Expand All @@ -89,6 +89,15 @@ You need to install ``mypy-extensions`` to use ``@mypyc_attr``:

pip install --upgrade mypy-extensions

Additionally, mypyc recognizes these base classes as special, and
understands how they alter the behavior of classes (including native
classes) that subclass them:

* ``typing.NamedTuple``
* ``typing.Generic``
* ``typing.Protocol``
* ``enum.Enum``

Class variables
---------------

Expand Down Expand Up @@ -145,7 +154,8 @@ behavior is too dynamic. You can use these metaclasses, however:
.. note::

If a class definition uses an unsupported metaclass, *mypyc
compiles the class into a regular Python class*.
compiles the class into a regular Python class* (non-native
class).

Class decorators
----------------
Expand All @@ -165,7 +175,63 @@ efficient as pure native classes.
.. note::

If a class definition uses an unsupported class decorator, *mypyc
compiles the class into a regular Python class*.
compiles the class into a regular Python class* (non-native class).

Defining non-native classes
---------------------------

You can use the ``@mypy_extensions.mypyc_attr(...)`` class decorator
with an argument ``native_class=False`` to explicitly define normal
Python classes (non-native classes)::

from mypy_extensions import mypyc_attr

@mypyc_attr(native_class=False)
class NonNative:
def __init__(self) -> None:
self.attr = 1

setattr(NonNative, "extra", 1) # Ok

This only has an effect in classes compiled using mypyc. Non-native
classes are significantly less efficient than native classes, but they
are sometimes necessary to work around the limitations of native classes.

Non-native classes can use arbitrary metaclasses and class decorators,
and they support flexible multiple inheritance. Mypyc will still
generate a compile-time error if you try to assign to a method, or an
attribute that is not defined in a class body, since these are static
type errors detected by mypy::

o = NonNative()
o.extra = "x" # Static type error: "extra" not defined

However, these operations still work at runtime, including in modules
that are not compiled using mypyc. You can also use ``setattr`` and
``getattr`` for dynamic access of arbitrary attributes. Expressions
with an ``Any`` type are also not type checked statically, allowing
access to arbitrary attributes::

a: Any = o
a.extra = "x" # Ok

setattr(o, "extra", "y") # Also ok

Implicit non-native classes
---------------------------

If a compiled class uses an unsupported metaclass or an unsupported
class decorator, it will implicitly be a non-native class, as
discussed above. You can still use ``@mypyc_attr(native_class=False)``
to explicitly mark it as a non-native class.

Explicit native classes
-----------------------

You can use ``@mypyc_attr(native_class=True)`` to explicitly declare a
class as a native class. It will be a compile-time error if mypyc
can't compile the class as a native class. You can use this to avoid
accidentally defining implicit non-native classes.

Deleting attributes
-------------------
Expand Down