.. _native-classes: Native classes ============== Classes in compiled modules are *native classes* by default (some exceptions are discussed below). Native classes are compiled to C extension classes, which have some important differences from normal Python classes. Native classes are similar in many ways to built-in types, such as ``int``, ``str``, and ``list``. Immutable namespaces -------------------- The type object namespace of native classes is mostly immutable (but class variables can be assigned to):: class Cls: def method1(self) -> None: print("method1") def method2(self) -> None: print("method2") Cls.method1 = Cls.method2 # Error Cls.new_method = Cls.method2 # Error Only attributes defined within a class definition (or in a base class) can be assigned to (similar to using ``__slots__``):: class Cls: x: int def __init__(self, y: int) -> None: self.x = 0 self.y = y def method(self) -> None: self.z = "x" o = Cls(0) print(o.x, o.y) # OK o.z = "y" # OK o.extra = 3 # Error: no attribute "extra" .. _inheritance: Inheritance ----------- Only single inheritance is supported (except for :ref:`traits `). Most non-native classes can't be used as base classes. These non-native classes can be used as base classes of native classes: * ``object`` * ``dict`` (and ``Dict[k, v]``) * ``BaseException`` * ``Exception`` * ``ValueError`` * ``IndexError`` * ``LookupError`` * ``UserWarning`` 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 defines the class. You can enable these through ``mypy_extensions.mypyc_attr``:: from mypy_extensions import mypyc_attr @mypyc_attr(allow_interpreted_subclasses=True) class Cls: ... Allowing interpreted subclasses has only minor impact on performance of instances of the native class. Accessing methods and attributes of a *non-native* subclass (or a subclass defined in another compilation unit) will be slower, since it needs to use the normal Python attribute access mechanism. You need to install ``mypy-extensions`` to use ``@mypyc_attr``: .. code-block:: text pip install --upgrade mypy-extensions Class variables --------------- Class variables must be explicitly declared using ``attr: ClassVar`` or ``attr: ClassVar[]``. You can't assign to a class variable through an instance. Example:: from typing import ClassVar class Cls: cv: ClassVar = 0 Cls.cv = 2 # OK o = Cls() print(o.cv) # OK (2) o.cv = 3 # Error! Generic native classes ---------------------- Native classes can be generic. Type variables are *erased* at runtime, and instances don't keep track of type variable values. Compiled code thus can't check the values of type variables when performing runtime type checks. These checks are delayed to when reading a value with a type variable type:: from typing import TypeVar, Generic, cast T = TypeVar('T') class Box(Generic[T]): def __init__(self, item: T) -> None: self.item = item x = Box(1) # Box[int] y = cast(Box[str], x) # OK (type variable value not checked) y.item # Runtime error: item is "int", but "str" expected Metaclasses ----------- Most metaclasses aren't supported with native classes, since their behavior is too dynamic. You can use these metaclasses, however: * ``abc.ABCMeta`` * ``typing.GenericMeta`` (used by ``typing.Generic``) .. note:: If a class definition uses an unsupported metaclass, *mypyc compiles the class into a regular Python class*. Class decorators ---------------- Similar to metaclasses, most class decorators aren't supported with native classes, as they are usually too dynamic. These class decorators can be used with native classes, however: * ``mypy_extensions.trait`` (for defining :ref:`trait types `) * ``mypy_extensions.mypyc_attr`` (see :ref:`above `) * ``dataclasses.dataclass`` Dataclasses have partial native support, and they aren't as efficient as pure native classes. .. note:: If a class definition uses an unsupported class decorator, *mypyc compiles the class into a regular Python class*. Deleting attributes ------------------- By default, attributes defined in native classes can't be deleted. You can explicitly allow certain attributes to be deleted by using ``__deletable__``:: class Cls: x: int = 0 y: int = 0 other: int = 0 __deletable__ = ['x', 'y'] # 'x' and 'y' can be deleted o = Cls() del o.x # OK del o.y # OK del o.other # Error You must initialize the ``__deletable__`` attribute in the class body, using a list or a tuple expression with only string literal items that refer to attributes. These are not valid:: a = ['x', 'y'] class Cls: x: int y: int __deletable__ = a # Error: cannot use variable 'a' __deletable__ = ('a',) # Error: not in a class body Other properties ---------------- Instances of native classes don't usually have a ``__dict__`` attribute.