如何在python中创建Callable的非泛型TypeAlias

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

我已经成功地(这样 mypy 不会抱怨)为带有参数的装饰器编写了类型提示,这些参数装饰了 python 3.11.9 中的类方法:

import functools
from typing import Callable, TypeVar


MyClassType = TypeVar("MyClassType", bound=object)
T = TypeVar("T")


def reader(uri: str) -> Callable[[Callable[[MyClassType], T]], Callable[[MyClassType], T]]:
    def decorator(fun: Callable[[MyClassType], T]) -> Callable[[MyClassType], T]:
        @functools.wraps(fun)
        def wrapper(subsys: MyClassType) -> T:
            return fun(subsys)
        wrapper.uri = uri
        return wrapper
    return decorator


def writer(uri: str) -> Callable[[Callable[[MyClassType, T], None]], Callable[[MyClassType, T], None]]:
    def decorator(fun: Callable[[MyClassType, T], None]) -> Callable[[MyClassType, T], None]:
        @functools.wraps(fun)
        def wrapper(subsys: MyClassType, value: T) -> None:
            fun(subsys, value)
        wrapper.uri = uri
        return wrapper
    return decorator


class MyClass:
    @reader("test")
    def _my_reader(self) -> int:
        return 1

    @writer("test")
    def _my_writer(self, val: float) -> None:
        print(val)

现在我想缩短装饰器的返回类型提示,如下所示:

import functools
from typing import Callable, TypeVar, TypeAlias


MyClassType = TypeVar("MyClassType", bound=object)
T = TypeVar("T")

ReaderMethod: TypeAlias = Callable[[MyClassType], T]
WriterMethod: TypeAlias = Callable[[MyClassType, T], None]

# ReaderMethod = TypeVar("ReaderMethod", bound=Callable[[MyClassType], T])
# WriterMethod = TypeVar("WriterMethod", bound=Callable[[MyClassType, T], None])


def reader(uri: str) -> Callable[[ReaderMethod], ReaderMethod]:
    def decorator(fun: ReaderMethod) -> ReaderMethod:
        @functools.wraps(fun)
        def wrapper(subsys: MyClassType) -> T:
            return fun(subsys)
        wrapper.uri = uri
        return wrapper
    return decorator


def writer(uri: str) -> Callable[[WriterMethod], WriterMethod]:
    def decorator(fun: WriterMethod) -> WriterMethod:
        @functools.wraps(fun)
        def wrapper(subsys: MyClassType, value: T) -> None:
            fun(subsys, value)
        wrapper.uri = uri
        return wrapper
    return decorator


class MyClass:
    @reader("test")
    def _my_reader(self) -> int:
        return 1

    @writer("test")
    def _my_writer(self, val: float) -> None:
        print(val)

未注释或注释版本的 ReaderMethod/WriterMethod 都不起作用,mypy 抱怨第 18 行,例如“返回 TypeVar 的函数应该接收至少一个包含相同 TypeVar 的参数”,以及其他(类型提示)问题。我做错了什么?如何改进我的类型提示,以便我拥有这些别名 ReaderMethod/WriterMethod 并且 mypy 很高兴?

编辑:在第 15 行,mypy 抱怨“缺少泛型类型“ReaderMethod”的类型参数”,因此是问题的标题。

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

仅仅因为您定义了通用别名并不意味着您可以停止使用类型变量。

MyClassType
T
ReaderMethod
的使用中并不是“隐含”的,而是默默地传递到
wrapper
的定义。

您可能还需要一个别名来定义“变压器”类型。

type Transformer[F] = Callable[[F], F]

def reader(uri: str)[A, RV] -> Transformer[ReaderMethod[A, RV]]:
    def decorator(fun: ReaderMethod[[A], RV]) -> ReaderMethod[[A], RV]:
        @functools.wraps(fun)
        def wrapper(subsys: A) -> RV:
            return fun(subsys)
        wrapper.uri = uri
        return wrapper
    return decorator
© www.soinside.com 2019 - 2024. All rights reserved.