Skip to content

Commit 334469f

Browse files
committed
[mypyc] Improve documentation of native and non-native classes (#19154)
Also discuss `mypyc_attr(native_class=<...>)`.
1 parent a499d9f commit 334469f

File tree

1 file changed

+74
-8
lines changed

1 file changed

+74
-8
lines changed

mypyc/doc/native_classes.rst

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ can be assigned to (similar to using ``__slots__``)::
4848
Inheritance
4949
-----------
5050

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

55-
These non-native classes can be used as base classes of native
57+
These non-native extension classes can be used as base classes of native
5658
classes:
5759

5860
* ``object``
@@ -63,8 +65,6 @@ classes:
6365
* ``IndexError``
6466
* ``LookupError``
6567
* ``UserWarning``
66-
* ``typing.NamedTuple``
67-
* ``enum.Enum``
6868

6969
By default, a non-native class can't inherit a native class, and you
7070
can't inherit from a native class outside the compilation unit that
@@ -89,6 +89,15 @@ You need to install ``mypy-extensions`` to use ``@mypyc_attr``:
8989
9090
pip install --upgrade mypy-extensions
9191
92+
Additionally, mypyc recognizes these base classes as special, and
93+
understands how they alter the behavior of classes (including native
94+
classes) that subclass them:
95+
96+
* ``typing.NamedTuple``
97+
* ``typing.Generic``
98+
* ``typing.Protocol``
99+
* ``enum.Enum``
100+
92101
Class variables
93102
---------------
94103

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

147156
If a class definition uses an unsupported metaclass, *mypyc
148-
compiles the class into a regular Python class*.
157+
compiles the class into a regular Python class* (non-native
158+
class).
149159

150160
Class decorators
151161
----------------
@@ -165,7 +175,63 @@ efficient as pure native classes.
165175
.. note::
166176

167177
If a class definition uses an unsupported class decorator, *mypyc
168-
compiles the class into a regular Python class*.
178+
compiles the class into a regular Python class* (non-native class).
179+
180+
Defining non-native classes
181+
---------------------------
182+
183+
You can use the ``@mypy_extensions.mypyc_attr(...)`` class decorator
184+
with an argument ``native_class=False`` to explicitly define normal
185+
Python classes (non-native classes)::
186+
187+
from mypy_extensions import mypyc_attr
188+
189+
@mypyc_attr(native_class=False)
190+
class NonNative:
191+
def __init__(self) -> None:
192+
self.attr = 1
193+
194+
setattr(NonNative, "extra", 1) # Ok
195+
196+
This only has an effect in classes compiled using mypyc. Non-native
197+
classes are significantly less efficient than native classes, but they
198+
are sometimes necessary to work around the limitations of native classes.
199+
200+
Non-native classes can use arbitrary metaclasses and class decorators,
201+
and they support flexible multiple inheritance. Mypyc will still
202+
generate a compile-time error if you try to assign to a method, or an
203+
attribute that is not defined in a class body, since these are static
204+
type errors detected by mypy::
205+
206+
o = NonNative()
207+
o.extra = "x" # Static type error: "extra" not defined
208+
209+
However, these operations still work at runtime, including in modules
210+
that are not compiled using mypyc. You can also use ``setattr`` and
211+
``getattr`` for dynamic access of arbitrary attributes. Expressions
212+
with an ``Any`` type are also not type checked statically, allowing
213+
access to arbitrary attributes::
214+
215+
a: Any = o
216+
a.extra = "x" # Ok
217+
218+
setattr(o, "extra", "y") # Also ok
219+
220+
Implicit non-native classes
221+
---------------------------
222+
223+
If a compiled class uses an unsupported metaclass or an unsupported
224+
class decorator, it will implicitly be a non-native class, as
225+
discussed above. You can still use ``@mypyc_attr(native_class=False)``
226+
to explicitly mark it as a non-native class.
227+
228+
Explicit native classes
229+
-----------------------
230+
231+
You can use ``@mypyc_attr(native_class=True)`` to explicitly declare a
232+
class as a native class. It will be a compile-time error if mypyc
233+
can't compile the class as a native class. You can use this to avoid
234+
accidentally defining implicit non-native classes.
169235

170236
Deleting attributes
171237
-------------------

0 commit comments

Comments
 (0)