Python 如何使用 __wrapped__ 键入提示 Callable

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

传递函数时,我通常用

typing.Callable
来提示它们。

collections.abc.Callable
的文档声明它有四种 dunder 方法:

集合类.abc.Callable

分别提供方法

__contains__()
__hash__()
__len__()
__call__()
的类的 ABC。

有一次,我想检查函数上是否有

__wrapped__
属性。 通过使用
hasattr(func, "__wrapped__")
检查,这可以在运行时正常工作。

使用

mypy
进行静态类型检查时,会报告:
error: "Callable[..., Any]" has no attribute "__wrapped__"  [attr-defined]
。 这对我来说很有意义,因为
Callable
不应该有
__wrapped__
属性。

如何正确输入带有

Callable
属性的提示
__wrapped__
? 我可以做一些其他类型的提示或解决方法吗?


代码示例

我正在使用

mypy==0.782
Python==3.8.2
:

from functools import wraps
from typing import Callable


def print_int_arg(arg: int) -> None:
    """Print the integer argument."""
    print(arg)


@wraps(print_int_arg)
def wrap_print_int_arg(arg: int) -> None:
    print_int_arg(arg)
    # do other stuff


def print_is_wrapped(func: Callable) -> None:
    """Print if a function is wrapped."""
    if hasattr(func, "__wrapped__"):
        # error: "Callable[..., Any]" has no attribute "__wrapped__"  [attr-defined]
        print(f"func named {func.__name__} wraps {func.__wrapped__.__name__}.")


print_is_wrapped(wrap_print_int_arg)
python python-typing mypy
2个回答
3
投票

显然,简单的答案是添加

# type: ignore
评论。 然而,这实际上并没有解决问题,IMO。

我决定为具有

__wrapped__
属性的可调用对象创建一个类型存根。 基于这个答案,这是我当前的解决方案:

from typing import Callable, cast


class WrapsCallable:
    """Stub for a Callable with a __wrapped__ attribute."""

    __wrapped__: Callable

    __name__: str

    def __call__(self, *args, **kwargs):
        ...


def print_is_wrapped(func: Callable) -> None:
    """Print if a function is wrapped."""
    if hasattr(func, "__wrapped__"):
        func = cast(WrapsCallable, func)
        print(f"func named {func.__name__} wraps {func.__wrapped__.__name__}.")

并且

mypy
现在报告
Success: no issues found in 1 source file

我觉得这似乎是很多样板代码,并且希望有一个更精简的答案。


2
投票

Mypy 抱怨在打印语句中使用

__wrapped__
。 下面的技巧让 mypy 高兴

def print_is_wrapped(func: Callable) -> None:
    """Print if a function is wrapped."""
    if hasattr(func, "__wrapped__"):
        wrapped_name = getattr(func, "__wrapped__").__name__
        print(f"func named {func.__name__} wraps {wrapped_name}.")
© www.soinside.com 2019 - 2024. All rights reserved.