Python 类型:使用像 Java Clazz<T> 中的 Clazz[T] 这样的泛型返回类型

bob*_*ing 2 python generics type-hinting python-3.x python-typing

所以我知道Python的typing.Optional. 但我编写了自己的粗略代码PyOptional此处为代码),并希望Optional[T]与我的PyOptionalto结合起来PyOptional[T]

我目前正在使用 Python 3.7 并尝试扩展typing.Optional.

我的一些PyOptional

class PyOptional:
    T: TypeVar = TypeVar("T")

    def __init__(self, obj: T):
        self.value: Any = obj

    def get(self) -> Optional[T]:
        return self.value

    def or_else(self, default) -> T:
        return self.value or default
Run Code Online (Sandbox Code Playgroud)

我想要的伪代码:

def find_user_by_id(id: int) -> PyOptional[User]:
    return PyOptional(db.find_user_by_id(id))
Run Code Online (Sandbox Code Playgroud)

我的目标是让 IDE 能够检查预期的返回类型,并且仍然能够在返回的对象上调用我的方法。因此它必须符合 PEP 要求。

Mic*_*x2a 5

您应该查看有关泛型的文档——特别是用户定义的泛型。mypy 文档还对泛型进行了全面的概述,可供参考。

Generic[T]在这种特殊情况下,您希望通过添加 a作为类基来使整个类通用。仅T在各个函数签名中使用将使每个单独的函数通用,但不会使整个类通用:

from typing import TypeVar, Generic, Optional

T = TypeVar("T")

class PyOptional(Generic[T]):
    def __init__(self, obj: Optional[T]) -> None:
        self.value = obj

    def get(self) -> Optional[T]:
        return self.value

    def or_else(self, default: T) -> T:
        return self.value or default
Run Code Online (Sandbox Code Playgroud)

一些附加说明:

  1. 不要为任何 TypeVar 变量添加注释。这里,T是一种元类型构造,充当“洞”/可以表示任意数量的类型。因此,为它分配固定类型实际上没有意义,并且会使类型检查器感到困惑。

  2. 切勿在任何给定签名中仅使用 TypeVar 一次 - 使用 TypeVar 的全部意义在于,您可以声明两个或多个类型始终相同。

    请注意,上面固定的 PyOptional 类也遵循此规则。例如,采取get. 现在我们使整个类变得通用,该函数的类型签名现在基本上类似于def get(self: PyOptional[T]) -> Optional[T]. 以前,它更像是def get(self: PyOptional) -> Optional[T]

  3. 为了让你的类有意义,你可能希望你的构造函数接受 anOptional[T]而不仅仅是T.

  4. 制作self.valueAny 可能是不必要的/不必要地太模糊。我们可以省略类型提示,现在它将具有推断类型Optional[T].

  5. 如果您想更彻底地检查您的类是否符合 PEP 484 并可能被 PyCharm 等 IDE 理解,请考虑通过 mypy(一个PEP 484 类型检查器)使用您的类对您的类和一些代码进行类型检查。

    这不能保证您的 IDE 将完全理解您的类(因为它可能无法完全实现有关 PEP 484 的所有内容/您可能会在 mypy 或您的 IDE 中遇到错误),但它应该可以帮助您非常接近。