Python 输入:return 使用 Clazz[T] 等泛型输入 Java Clazz<T>
Python typing: return type with generics like Clazz[T] as in Java Clazz<T>
所以我知道 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 能够检查预期的 return 类型并且仍然能够在 returned 对象上调用我的方法。所以它必须符合 PEP。
您应该查看有关泛型的文档 -- 具体来说,user-defined generics. The mypy docs also have a thorough overview of generics 可以作为参考。
在这种特殊情况下,您希望通过添加 Generic[T]
作为 class 基础来使整个 class 通用。仅在单独的函数签名中使用 T
将使每个 单独的 函数通用,但不是整个 class:
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——使用 TypeVars 的全部意义在于你可以声明两个或多个类型总是相同的。
注意上面固定的PyOptionalclass也遵守这个规则。例如,取 get
。现在我们将整个 class 变成了泛型,这个函数的类型签名现在基本上类似于 def get(self: PyOptional[T]) -> Optional[T]
。以前更像是def get(self: PyOptional) -> Optional[T]
.
为了使 class 有意义,您可能希望构造函数接受 Optional[T]
而不仅仅是 T
.
使 self.value
Any 可能 unnecessary/is 过于含糊。我们可以省略类型提示,现在它的推断类型为 Optional[T]
.
如果您想更彻底地检查您的 class 是否符合 PEP 484 并且可能会被 IDE 理解,例如 PyCharm,考虑通过 mypy 使用 class 对 class + 一些代码进行类型检查,PEP 484 类型检查器。
这不能保证您的 IDE 会完全理解您的 class(因为它可能无法完全实现关于 PEP 484 的所有内容/您可能 运行 mypy 或你的 IDE),但它应该可以帮助你接近。
所以我知道 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 能够检查预期的 return 类型并且仍然能够在 returned 对象上调用我的方法。所以它必须符合 PEP。
您应该查看有关泛型的文档 -- 具体来说,user-defined generics. The mypy docs also have a thorough overview of generics 可以作为参考。
在这种特殊情况下,您希望通过添加 Generic[T]
作为 class 基础来使整个 class 通用。仅在单独的函数签名中使用 T
将使每个 单独的 函数通用,但不是整个 class:
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——使用 TypeVars 的全部意义在于你可以声明两个或多个类型总是相同的。
注意上面固定的PyOptionalclass也遵守这个规则。例如,取
get
。现在我们将整个 class 变成了泛型,这个函数的类型签名现在基本上类似于def get(self: PyOptional[T]) -> Optional[T]
。以前更像是def get(self: PyOptional) -> Optional[T]
.为了使 class 有意义,您可能希望构造函数接受
Optional[T]
而不仅仅是T
.使
self.value
Any 可能 unnecessary/is 过于含糊。我们可以省略类型提示,现在它的推断类型为Optional[T]
.如果您想更彻底地检查您的 class 是否符合 PEP 484 并且可能会被 IDE 理解,例如 PyCharm,考虑通过 mypy 使用 class 对 class + 一些代码进行类型检查,PEP 484 类型检查器。
这不能保证您的 IDE 会完全理解您的 class(因为它可能无法完全实现关于 PEP 484 的所有内容/您可能 运行 mypy 或你的 IDE),但它应该可以帮助你接近。