如何正确键入提示修饰的 __getitem__ 和 __setitem__

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

例如:

T = TypeVar("T", bound="CustomDict")

class CustomDict(dict):
    def __init__(self) -> None:
        super().__init__()

    class dict_operator:
        def __init__(self, method: Callable[..., Any]) -> None:
            self.method = method

        def __get__(self, instance: T, owner: Type[T]) -> Callable[..., Any]:
            def wrapper(key: Any, *args: Any, **kwargs: Any) -> Any:
                results = self.method(instance, key, *args, **kwargs)

                print("Did something after __getitem__ or __setitem__")
                return results

            return wrapper

    @dict_operator
    def __getitem__(self, key: Any) -> Any:
        return super().__getitem__(key)

    @dict_operator
    def __setitem__(self, key: Any, value: Any) -> None:
        super().__setitem__(key, value)

我的:

Signature of "__getitem__" incompatible with supertype "dict"Mypyoverride Signature of "__getitem__" incompatible with supertype "Mapping"Mypyoverride (variable) Any: Any

我认为装饰器更改了重写方法的签名,但我不知道如何解释这一点。

python decorator mypy typing
1个回答
0
投票

问题不在于

__getitem__
__setitem__
上的类型注释。无论好坏,mypy(目前)都无法识别返回
__get__
Callable
在大多数情况下是代替真正的
Callable
的安全覆盖。最快的解决方法是将
__call__
添加到您的
dict_operator
类主体 (mypy Playground 1):

class CustomDict(dict):
    ...
    class dict_operator:
        def __init__(self, method: Callable[..., Any]) -> None: ...
        def __get__(self, instance: T, owner: Type[T]) -> Callable[..., Any]: 
        # This needs to be the same as the return type of `__get__`
        __call__: Callable[..., Any]
    
    @dict_operator
    def __getitem__(self, key: Any) -> Any: ...  # OK

    @dict_operator
    def __setitem__(self, key: Any, value: Any) -> None: ... # OK

我不知道你这样做是否只是为了演示目的,但在我看来,你在这里输入的内容太多不精确;特别是

Callable[..., Any]
不是一个非常有用的类型注释。我不知道您使用的是哪个 Python 版本,但如果您能够使用
typing_extensions
代替,您就可以访问最新的类型结构以进行更好的静态检查。请参阅 mypy Playground 2 了解实现更严格打字的可能方法。

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