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

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)的修饰符很有用,但在几乎所有情况下,TInTOut是相同的,因此我想简化我的定义的使用.

从本质上讲,我希望这样做:如果没有给出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不支持缺省值,没有完全定义的泛型就是未知的.也许它应该支持它,这个特性有一个草案(见下面的更新).

目前,我将创建两个公开不同接口的类.这几乎是一样好的,它只是意味着你需要第二节课:

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

我所说的"对称"只是指可调用对象接收并返回相同的类型--可能有一个更好的名称.希望这是有用的!

UPDATE:之后,我发现TypeVar:https://peps.python.org/pep-0696/的默认值存在活动的PEP

Python相关问答推荐

Asyncio与队列的多处理通信-仅运行一个协程

try 使用tensorFlow.keras.models时optree Import错误

定义同侪组并计算同侪组分析

Flask主机持续 bootstrap 本地IP| Python

如何从格式为note:{neighbor:weight}的字典中构建networkx图?

在两极中实施频率编码

使用matplotlib pcolormesh,如何停止从一行绘制的磁贴连接到上下行?

Python中的负前瞻性regex遇到麻烦

如何使用SubProcess/Shell从Python脚本中调用具有几个带有html标签的参数的Perl脚本?

在内部列表上滚动窗口

如何使用LangChain和AzureOpenAI在Python中解决AttribeHelp和BadPressMessage错误?

在线条上绘制表面

为什么默认情况下所有Python类都是可调用的?

NP.round解算数据后NP.unique

基于索引值的Pandas DataFrame条件填充

如何合并两个列表,并获得每个索引值最高的列表名称?

在Python中使用if else或使用regex将二进制数据如111转换为001""

Flask Jinja2如果语句总是计算为false&

Python—压缩叶 map html作为邮箱附件并通过sendgrid发送

巨 Python :逆向猜谜游戏