如何在 Python 的泛型类中拥有可选的 TypeVar?

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

我正在尝试编写一个简单的类型包装器来表示装饰器函数的接口:

from typing import Protocol, TypeVar, Generic

TIn = TypeVar('TIn', contravariant=True)
TOut = TypeVar('TOut', covariant=True)

class Decorator(Protocol, Generic[TIn, TOut]):
    """
    Represents a decorated value, used to simplify type definitions
    """
    def __call__(self, value: TIn) -> TOut:
        ...

这将用于键入装饰器函数,如下所示:

IntFunction = Callable[[int, int], int]


def register_operator(op: str) -> Decorator[IntFunction, IntFunction]:
    def inner(value: IntFunction) -> IntFunction:
        # register the function or whatever
        return value
    return inner


@register_operator("+")
def add(a: int, b: int) -> int:
    return a + b

在上面的示例中,Mypy 能够验证

add
的类型签名,以确保它符合
register_operator
的规范。

这对于转换类型的装饰器很有用(例如将其从

IntFunction
转换为
StrFunction
),但在几乎所有情况下,
TIn
TOut
相同,所以我想简化用法我的定义。

本质上,我想这样做,如果没有给出

TOut
,它将被假定为与
TIn
相同,这将允许上面的装饰器函数简化为

def register_operator(op: str) -> Decorator[IntFunction]:
    #                              Simplification here ^

    def inner(value: IntFunction) -> IntFunction:
        # register the function or whatever
        return value
    return inner

我在协议定义中使用的理想语法将是这样的:

class Decorator(Protocol, Generic[TIn, TOut = TIn]):
    """
    Represents a decorated value, used to simplify type definitions
    """
    def __call__(self, value: TIn) -> TOut:
        ...

请注意,这不起作用。

如何实现此功能,同时继续获得 Mypy 提供的保证?我很高兴根据需要使

Decorator
的定义变得复杂,但我想保持其简单的用法。

python generics mypy python-typing typing
1个回答
0
投票

据我所知,python 不支持泛型中的默认值,未完全定义的泛型将变得未知。也许它应该支持它,有一个针对此功能的草稿(请参阅下面的更新)。

现在,我将创建两个公开不同接口的类。这几乎一样好,只是意味着您需要第二堂课:

from typing import Protocol, TypeVar, Generic, overload

TIn = TypeVar('TIn', contravariant=True)
TOut = TypeVar('TOut', covariant=True)
TSym = TypeVar('TSym')

class Decorator(Protocol, Generic[TIn, TOut]):
    """
    Represents a decorated value, used to simplify type definitions
    """
    def __call__(self, value: TIn) -> TOut:
        ...

class SymmetricDecorator(Decorator[TSym,TSym], Generic[TSym], Protocol):
    pass

“对称”我只是指可调用接收并返回相同的类型 - 可能有更好的名称。希望这有用!

更新:我发现 TypeVar 的默认值存在一个活动的 pep:https://peps.python.org/pep-0696/

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