通过类型注释抽象 Python 中的类型构造函数
Abstracting over type constructors in Python via type annotations
我想静态地强制执行一个 class return 的方法,一个包装在某种抽象类型中的值,我对此一无所知:
例如给定摘要 class
F = ???
class ThingF(Generic[F]):
@abstractmethod
def action(self) -> F[Foo]:
...
我希望能够静态检查这是否无效:
class ThingI(ThingF[List]):
def action(self) -> Foo:
...
因为 action
没有 return List[Foo]
.
但是 ThingF
的上述声明甚至没有 运行,因为 Generic
期望它的参数是类型变量,而我找不到使 F
的方法类型变量 "with a hole".
两者都
F = TypeVar('F')
和
T = TypeVar('T')
F = Generic[T]
不起作用,因为 TypeVar
不可下标或 Generic[~T]
不能用作类型变量。
基本上我想要的是 "higher kinded type variable",类型构造函数的抽象,如果您愿意的话。 IE。上面写着 "F can be any type that takes another type to produce a concrete type".
的东西
有什么方法可以用 Python 的类型注释来表达它并用 mypy
进行静态检查吗?
不幸的是,类型系统(如 PEP 484 中所述)不支持更高种类的类型——这里有一些相关的讨论:https://github.com/python/typing/issues/548。
mypy 和其他类型检查工具可能会在将来的某个时候获得对它们的支持,但我不会屏住呼吸。这需要一些相当复杂的实施工作才能完成。
您可以将更高种类的类型与 dry-python/returns
一起使用。
我们同时发布原语和自定义 mypy
插件以使其正常工作。
这是一个 Mappable
又名 Functor
的例子:
from typing import Callable, TypeVar
from returns.interfaces.mappable import MappableN
from returns.primitives.hkt import Kinded, KindN, kinded
_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')
_UpdatedType = TypeVar('_UpdatedType')
_MappableKind = TypeVar('_MappableKind', bound=MappableN)
@kinded
def map_(
container: KindN[_MappableKind, _FirstType, _SecondType, _ThirdType],
function: Callable[[_FirstType], _UpdatedType],
) -> KindN[_MappableKind, _UpdatedType, _SecondType, _ThirdType]:
return container.map(function)
它适用于任何 Mappable
、examples:
from returns.maybe import Maybe
def test(arg: float) -> int:
...
reveal_type(map_(Maybe.from_value(1.5), test)) # N: Revealed type is 'returns.maybe.Maybe[builtins.int]'
并且:
from returns.result import Result
def test(arg: float) -> int:
...
x: Result[float, str]
reveal_type(map_(x, test)) # N: Revealed type is 'returns.result.Result[builtins.int, builtins.str]'
它肯定有一些限制,比如:它只适用于直接的 Kind
子类型,我们需要一个单独的别名 Kind1
、Kind2
、Kind3
,等。因为当时 mypy
不支持可变泛型。
来源:https://github.com/dry-python/returns/blob/master/returns/primitives/hkt.py
插件:https://github.com/dry-python/returns/blob/master/returns/contrib/mypy/_features/kind.py
文档:https://returns.readthedocs.io/en/latest/pages/hkt.html
公告post:https://sobolevn.me/2020/10/higher-kinded-types-in-python
我想静态地强制执行一个 class return 的方法,一个包装在某种抽象类型中的值,我对此一无所知:
例如给定摘要 class
F = ???
class ThingF(Generic[F]):
@abstractmethod
def action(self) -> F[Foo]:
...
我希望能够静态检查这是否无效:
class ThingI(ThingF[List]):
def action(self) -> Foo:
...
因为 action
没有 return List[Foo]
.
但是 ThingF
的上述声明甚至没有 运行,因为 Generic
期望它的参数是类型变量,而我找不到使 F
的方法类型变量 "with a hole".
两者都
F = TypeVar('F')
和
T = TypeVar('T')
F = Generic[T]
不起作用,因为 TypeVar
不可下标或 Generic[~T]
不能用作类型变量。
基本上我想要的是 "higher kinded type variable",类型构造函数的抽象,如果您愿意的话。 IE。上面写着 "F can be any type that takes another type to produce a concrete type".
的东西有什么方法可以用 Python 的类型注释来表达它并用 mypy
进行静态检查吗?
不幸的是,类型系统(如 PEP 484 中所述)不支持更高种类的类型——这里有一些相关的讨论:https://github.com/python/typing/issues/548。
mypy 和其他类型检查工具可能会在将来的某个时候获得对它们的支持,但我不会屏住呼吸。这需要一些相当复杂的实施工作才能完成。
您可以将更高种类的类型与 dry-python/returns
一起使用。
我们同时发布原语和自定义 mypy
插件以使其正常工作。
这是一个 Mappable
又名 Functor
的例子:
from typing import Callable, TypeVar
from returns.interfaces.mappable import MappableN
from returns.primitives.hkt import Kinded, KindN, kinded
_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')
_UpdatedType = TypeVar('_UpdatedType')
_MappableKind = TypeVar('_MappableKind', bound=MappableN)
@kinded
def map_(
container: KindN[_MappableKind, _FirstType, _SecondType, _ThirdType],
function: Callable[[_FirstType], _UpdatedType],
) -> KindN[_MappableKind, _UpdatedType, _SecondType, _ThirdType]:
return container.map(function)
它适用于任何 Mappable
、examples:
from returns.maybe import Maybe
def test(arg: float) -> int:
...
reveal_type(map_(Maybe.from_value(1.5), test)) # N: Revealed type is 'returns.maybe.Maybe[builtins.int]'
并且:
from returns.result import Result
def test(arg: float) -> int:
...
x: Result[float, str]
reveal_type(map_(x, test)) # N: Revealed type is 'returns.result.Result[builtins.int, builtins.str]'
它肯定有一些限制,比如:它只适用于直接的 Kind
子类型,我们需要一个单独的别名 Kind1
、Kind2
、Kind3
,等。因为当时 mypy
不支持可变泛型。
来源:https://github.com/dry-python/returns/blob/master/returns/primitives/hkt.py 插件:https://github.com/dry-python/returns/blob/master/returns/contrib/mypy/_features/kind.py
文档:https://returns.readthedocs.io/en/latest/pages/hkt.html
公告post:https://sobolevn.me/2020/10/higher-kinded-types-in-python