所以我知道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 要求。
您应该查看有关泛型的文档 - 具体来说,用户定义的泛型。 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
一些补充说明:
不要为任何 TypeVar 变量添加注释。这里,
T
是一种元类型构造,充当“洞”/可以表示任意数量的类型。因此,为它分配固定类型实际上没有意义,并且会让类型检查器感到困惑。
永远不要在任何给定的签名中仅使用 TypeVar 一次——使用 TypeVar 的全部意义在于,您可以声明两个或多个类型始终相同。
请注意,上面固定的 PyOptional 类也遵循此规则。例如,取
get
。现在我们使整个类变得通用,该函数的类型签名现在基本上类似于 def get(self: PyOptional[T]) -> Optional[T]
。以前,它更像是def get(self: PyOptional) -> Optional[T]
。
为了让你的类有意义,你可能希望你的构造函数接受
Optional[T]
而不是仅仅 T
。
制作
self.value
任何可能都是不必要的/不必要地太模糊。我们可以省略类型提示,现在它的推断类型为 Optional[T]
。
如果您想更彻底地检查您的类是否符合 PEP 484 并可能被 PyCharm 等 IDE 理解,请考虑通过 mypy(一种 PEP 484 类型)对您的类以及使用您的类的一些代码进行类型检查检查员。
这不能保证您的 IDE 将完全理解您的类(因为它可能无法完全实现有关 PEP 484 的所有内容/您可能会在 mypy 或您的 IDE 中遇到错误),但它应该可以帮助您非常接近。