| .. _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 |
| <trait-types>`). 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`` |
| * ``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 |
| 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[<type>]``. 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! |
| |
| .. tip:: |
| |
| Constant class variables can be declared using ``typing.Final`` or |
| ``typing.Final[<type>]``. |
| |
| 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 <trait-types>`) |
| * ``mypy_extensions.mypyc_attr`` (see :ref:`above <inheritance>`) |
| * ``dataclasses.dataclass`` |
| * ``@attr.s(auto_attribs=True)`` |
| |
| Dataclasses and attrs classes 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. |