Mypy 和二阶装饰器

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

我正在尝试实现一个二阶装饰器,它将动态变量注入作为装饰函数的第一个参数。

这是我到目前为止所拥有的:

from typing import Callable, Concatenate, ParamSpec, TypeVar

T = TypeVar('T')
U = TypeVar('U')
P = ParamSpec('P')


def foo(some_arg: U) -> Callable[
    [Callable[Concatenate[U, P], T]],
    Callable[P, T],
]:
    def decorator(fn: Callable[Concatenate[U, P], T]) -> Callable[P, T]:
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
            return fn(some_arg, *args, **kwargs)

        return wrapper

    return decorator

运行mypy时,出现以下错误:

error: Incompatible return value type (
    got "Callable[[Arg(Callable[[U, **P], T], 'fn')], Callable[P, T]]",
    expected "Callable[[Callable[[U, **P], T]], Callable[P, T]]")  [return-value]

我不明白我做错了什么。 我找不到 Mypy 所说的有关

Arg
元素的任何信息(在 mypy 文档中找不到
typing.Arg
)。

我应该如何声明我的装饰器工厂的返回值? 我应该如何解释 mypy 的此错误输出?我可能错过了文档中的任何来源吗?

python python-decorators type-hinting mypy python-typing
1个回答
0
投票

正如 @STerliakov 已经提到的,这很可能是一个错误。 但据我所知, mypy 遇到的困惑是,您指定返回带有一个未命名参数的可调用对象,而返回第一个参数称为

fn
的函数。这不是一个错误,因为您也可以按位置传递可选的命名参数(因此这是一个错误)。

如果您当前无法升级 mypy,使

fn
成为必须的位置参数(通过在签名中添加
/
),可能会解决您的问题:

    def decorator(fn: Callable[Concatenate[U, P], T], /) -> Callable[P, T]:
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
            return fn(some_arg, *args, **kwargs)

        return wrapper

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