类型约定

警告

本节仍在编写中。

为函数和参数添加类型提示

Manim 当前正在为库添加类型提示。本节将提供有关所用标准和一些通用准则的信息。

如果您从未接触过类型提示,这里是一个很好的入门点:https://realpython.com/python-type-checking/#hello-types

类型标准

Manim 使用 mypy 来检查其代码库的类型。您将在 mypy.ini 配置文件中找到配置值列表。为了能够使用在最低支持的 Python 版本中不可用的最新类型功能,请使用 typing_extensions

为了能够使用新的 Union 语法 (|) 和内置下标,请使用 from __future__ import annotations 导入。

类型准则

  • Manim 有一个专门的 typing 模块,其中提供了类型别名。它们中的大多数可能看起来是多余的,特别是与 numpy 相关的那些。这是为了预期对形状类型提示的支持(相关问题)。除了待定的形状支持之外,使用正确的类型别名将帮助用户理解应该使用哪种形状。

  • 有关泛型集合的类型,请查看链接。

  • 对于不返回值的函数(这也适用于 __init__),始终使用 None 类型提示,例如:

def height(self, value) -> None:
    self.scale_to_fit_height(value)
  • 对于表示路径的变量,请使用 typing 模块中定义的 StrPathStrOrBytesPath 类型别名。

  • *args**kwargs 不应未指定类型(在大多数情况下,您可以使用 Any)。

  • 遵循 PEP 484,使用 float 而不是 int | float

  • 使用 x | y 而不是 Union[x, y]

  • Mobject 具有类型提示 Mobject,例如:

def match_color(self, mobject: "Mobject"):
    """Match the color with the color of another :class:`~.Mobject`."""
    return self.set_color(mobject.get_color())
  • 始终对泛型进行参数化(使用 list[int] 而不是 list,使用 type[Any] 而不是 type 等)。这也适用于可调用对象。

rate_func: Callable[[float], float] = lambda t: smooth(1 - t)
  • 当您希望将类型提示“链接”为同一类型时,请使用 TypeVar。考虑 Mobject.copy,它返回同一类的新实例。其类型提示将是:

T = TypeVar("T")


def copy(self: T) -> T: ...
  • 只要函数与任何可迭代对象一起工作,而不是特定类型,就使用 typing.Iterable

  • 优先使用 numpy.typing.NDArray 而不是 numpy.ndarray

import numpy as np

if TYPE_CHECKING:
    import numpy.typing as npt


def foo() -> npt.NDArray[float]:
    return np.array([1, 0, 1])
  • 如果方法返回 self,请使用 typing_extensions.Self

if TYPE_CHECKING:
    from typing_extensions import Self


class CustomMobject:
    def set_color(self, color: ManimColor) -> Self:
        ...
        return self
  • 如果函数每次都返回特定长度的容器,请考虑使用 tuple 而不是 list

def foo() -> tuple[float, float, float]:
    return (0, 0, 0)
  • 如果函数处理的参数具有 __getitem____iter_____len__ 方法,则该参数的类型提示应为 collections.abc.Mapping。如果它还支持 __setitem__ 和/或 __delitem__,则应将其标记为 collections.abc.MutableMapping

  • 将某物类型提示为 object 意味着只能访问每个 Python 对象上可用的属性,例如 __str__ 等。另一方面,使用 Any 类型提示的变量可以访问字面意义上的任何属性——它比 object 类型提示更自由,并使 mypy 停止对该变量进行类型检查。请注意,在任何可能的情况下,尽量使类型提示尽可能具体。

  • 如果导入对象纯粹是为了类型提示目的,请将其置于 if typing.TYPE_CHECKING 保护之下,以防止它们在运行时被导入(有助于库性能)。不要忘记使用 from __future__ import annotations 导入,以避免出现运行时 NameError 异常。

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from manim.typing import Vector3D
# type stuff with Vector3D

类型提示的缺失部分是: