【问题标题】:mypy error: Callable has no attribute "__get__"mypy 错误:Callable 没有属性“__get__”
【发布时间】:2019-09-19 09:55:57
【问题描述】:

我有类似以下的内容:

from typing import TypeVar, Callable, Generic, Type, Union, Optional

T = TypeVar("T")
V = TypeVar("V")

class DescClass(Generic[T, V]):
    """A descriptor."""
    def __init__(self, func: Callable[[T], V]) -> None:
        self.func = func

    def __get__(self, instance: Optional[T], owner: Type[T]) -> Callable[[], V]:
        return self.func.__get__(instance, owner)

class C:
    @DescClass
    def f(self): ...

...Mypy 将返回此错误:

test.py:12: error: "Callable[[T], Any]" has no attribute "__get__"

func指定类型的规范方法是什么,以便Mypy理解它是一个描述符(and thus always has a __get__)?

更新:在搜索 Mypy 帮助时,“描述符”has no hits 有点幽默。

【问题讨论】:

  • @juanpa.arrivillaga 对。 class MyCallable: def __call__(self): ... 等等等等等等....
  • 也许是protocols/structural types的一个很好的用例
  • @FilipDimitrovski 因为未来(读作:愚蠢、健忘、粗心……)我可能会尝试使用函数式语法和一些可调用的非函数对象来修补补丁:C.g = DescClass(callable_obj),它会不工作。
  • @RickTeachey 我不得不放弃自己尝试合并协议,尽管它相当复杂(需要 classmethds 等),而且我不确定协议是否是问题的根源。我最终选择了 abc.ABC 。阅读this question 中的答案/cmets。您的用例可能很简单,以至于它“可以正常工作”,但它绝对不是一个可以投入生产的功能,至少这是我的印象。
  • 可以将描述符的类型定义class Descriptor(Protocol[T, V]): def __get__(self, instance: Optional[T], owner: Optional[Type[T]]) -> V: pass(如果需要数据描述符,请添加__set__/__del__)。当DescClass 设置为采用func: Descriptor[T, Callable[[], V]] 时,这将正常工作。然而,从 MyPy 0.812 开始,最终的问题是 def “创建”只是一个 Callable[[C], Any]" 没有任何信息表明它也是一个描述符。

标签: python callable mypy


【解决方案1】:

这似乎在现代 python 和现代 mypy 上运行良好:

from typing import (
    TypeVar,
    Callable,
    Generic, 
    Type, 
    Optional,
    cast,
    Protocol
)

T_contra = TypeVar("T_contra", contravariant=True)
V = TypeVar("V")
P_co = TypeVar("P_co", covariant=True)


class DescriptorProto(Protocol[P_co, T_contra]):
    def __get__(
        self, 
        instance: Optional[T_contra], 
        owner: Type[T_contra]
    ) -> P_co:
        ...


FuncType = DescriptorProto[Callable[[], V], T_contra]


class DescClass(Generic[T_contra, V]):
    """A descriptor."""

    def __init__(self, func: Callable[[T_contra], V]) -> None:
        self.func = cast(FuncType[V, T_contra], func)

    def __get__(
        self, 
        instance: Optional[T_contra], 
        owner: Type[T_contra]
    ) -> Callable[[], V]:
        return self.func.__get__(instance, owner)


class C:
    @DescClass
    def f(self) -> None: ...

【讨论】:

  • 不错!我想这已经修复(我还没有测试你的代码,但对我来说看起来不错!)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 2021-11-29
  • 2023-02-01
  • 2021-03-10
  • 2020-12-11
  • 1970-01-01
相关资源
最近更新 更多