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

问题描述 投票:0回答:1

所以我知道Python的

typing.Optional
。但我自己写了粗略的
PyOptional
(代码here),并希望将
Optional[T]
与我的
PyOptional
结合到
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

我想要的伪代码:

def find_user_by_id(id: int) -> PyOptional[User]:
    return PyOptional(db.find_user_by_id(id))

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

python generics python-typing
1个回答
5
投票

您应该查看有关泛型的文档 - 具体来说,用户定义的泛型。 mypy 文档还提供了全面的泛型概述,可供参考。

在这种特殊情况下,您希望通过添加

Generic[T]
作为类基来使整个类通用。仅在各个函数签名中使用
T
将使每个 individual 函数通用,但不是整个类:

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

一些补充说明:

  1. 不要为任何 TypeVar 变量添加注释。这里,

    T
    是一种元类型构造,充当“洞”/可以表示任意数量的类型。因此,为它分配固定类型实际上没有意义,并且会让类型检查器感到困惑。

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

    请注意,上面固定的 PyOptional 类也遵循此规则。例如,取

    get
    。现在我们使整个类变得通用,该函数的类型签名现在基本上类似于
    def get(self: PyOptional[T]) -> Optional[T]
    。以前,它更像是
    def get(self: PyOptional) -> Optional[T]

  3. 为了让你的类有意义,你可能希望你的构造函数接受

    Optional[T]
    而不是仅仅
    T

  4. 制作

    self.value
    任何可能都是不必要的/不必要地太模糊。我们可以省略类型提示,现在它的推断类型为
    Optional[T]

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

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

© www.soinside.com 2019 - 2024. All rights reserved.