子类装饰方法的类型不兼容 - python

Posted

技术标签:

【中文标题】子类装饰方法的类型不兼容 - python【英文标题】:Type incompatibility for subclass' decorated method - python 【发布时间】:2019-03-15 15:07:24 【问题描述】:

我遇到了一个错误

$ mypy python.py
python.py:34: error: Signature of "fn" incompatible with supertype "B"

python.py 在哪里

from typing import Callable, TypeVar, cast

T = TypeVar('T')


def dec(f: Callable[..., T]) -> T:
    def p(self):
        return getattr(self, '_' + f.__name__)

    return cast(T, property(p))


class X:
    pass


class Y(X):
    pass


class A:
    _fn = Y()


class B(A):
    @dec
    def fn(self) -> X:
        return X()


class C(B):
    @dec
    def fn(self) -> Y:
        return Y()

这里,装饰器dec 意味着做两件事

将对应的方法提升为属性 将调用重定向到名称带有附加下划线的属性

我不明白为什么 mypy 无法确定 Y 继承自 X。如果我将 -> Y 替换为 -> X,或者删除装饰器,则不会出现错误。

我已经用 mypy 0.630 和 Python 3.5.2、3.6.6 和 3.7.0 尝试过这个

编辑 正如 cmets 中所指出的,最初发布的 A._fn 的类型与 C.fn 不兼容。我已编辑 A._fn 以消除此问题。错误没有改变。

编辑一些上下文 - A 是一个配置模式类,看起来更像

class A:
     def __init__(self, **kwargs):
         for k, v in kwargs.items():
             setattr(self, '_' + k, v)

我们希望用户像c = C(fn=Y()); c.fn # gives a Y 一样使用它。最初该问题将A_.fn 作为返回Y()方法。更正这一点并不会影响错误

编辑我已将此作为一个 mypy 错误 https://github.com/python/mypy/issues/5836

【问题讨论】:

你能显示完整的错误信息吗? 我在运行这个文件时没有收到任何错误...你能显示你用来运行文件的完整命令吗?你用的是什么版本的 python & mypy? Y 不是X 那么这里是什么意思呢?您将一个承诺返回Y 的函数替换为一个返回X 的对象。您限制了返回值。任何调用C().fn() 的人都可以合理地期望能够使用Y() 方法和属性,但X() 不会拥有这些。这违反了您声明fn() 的合同。我通常会在这里指向covariance and contravariance,但你不能精确地在返回值上使用逆变,因为你不能仅仅删除这样的功能。 换一种说法,当装饰器承诺返回完全相同的类型时,为什么 Mypy 允许通过装饰器从 Y 转换到 Xdec 接受一个返回 TCallable,并生成 T 作为结果。 Y -> X 与该签名不匹配,并且从 YXsane 路径不会失去功能。 【参考方案1】:

我认为您的意思是 dec 将返回 Callable 而不是 T。 应该是:

def dec(f: Callable[..., T]) -> Callable[..., T]:
    def p(self):
       return getattr(self, '_' + f.__name__)

    return cast(Callable[..., T], property(p))

【讨论】:

我不是 100% 清楚这一点,但我不认为这是 Callable[..., T]。它应该是一个property,但由于在任何被称为 this 的语法上都具有与 T 相同的类型,所以我们可以安全地转换为 T

以上是关于子类装饰方法的类型不兼容 - python的主要内容,如果未能解决你的问题,请参考以下文章

@Patch 装饰器与 pytest 夹具不兼容

使用 UItableViewCell 类型的表达式初始化“CustomCellView *”的不兼容指针类型

TypeScript React HOC 返回类型与装饰器兼容

010.里式转换命名空间字段属性索引器

BOOL 与 Swift 4.1 中的 Bool 不兼容

android studio报错不兼容的类型。