如何在执行覆盖时获取方法中正确的注释签名顺序

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

我正在尝试修复魔法和普通方法的一些方法注释。例如,我有一些案例,如:

```

class Headers(typing.Mapping[str, str]):
    ...

    def __contains__(self, key: str) -> bool:
        ...
        return False

    def keys(self) -> typing.List[str]:
        ...
        return ['a', 'b']

```

当我运行mypy somefile.py --disallow-untyped-defs时,我有以下错误:

error: Argument 1 of "__contains__" incompatible with supertype "Mapping" error: Argument 1 of "__contains__" incompatible with supertype "Container" error: Return type of "keys" incompatible with supertype "Mapping"

我的理解是我需要使用@override装饰器覆盖方法,我需要尊重继承的顺序。这是对的吗?

如果我的假设是正确的,那么在哪里可以找到父类的确切签名?

python-3.6 mypy
1个回答
0
投票

在询问mypy的问题后,答案是:

子类化typing.Mapping[str, str],我假设包含的参数键的函数签名应该与泛型类型匹配?

contains不是通用方法 - 它被定义为包含类型签名(self,key:object) - > bool。你可以在typeshed上查看。这样定义包含的原因是因为在{“foo”:“bar”}中执行1这样的操作在技术上是合法的。

子类化def包含(self,key)到def包含(self,key:str)在任何情况下都更具体。更具体的子类型不违反Liskov,不是吗?

当你重写一个函数时,可以使参数类型更通用,返回类型更具体。也就是说,参数类型应该是逆变的并且返回类型是协变的。

如果我们不遵守规则,我们最终可能会在代码中引入错误。例如:

class Parent:
    def foo(self, x: object) -> None: ...

class Child(Parent):
    def foo(self, x: str) -> None: ...

def test(x: Parent) -> None:
    x.foo(300)  # Safe if 'x' is actually a Parent, not safe if `x` is actually a Child.

test(Child())

因为我们打破了liskov,将一个Child实例传入测试最终引入了一个bug。

基本上,如果我在Any上使用key __contains__方法是正确的,mypy不会抱怨:

 def __contains__(self, key: typing.Any) -> bool:
    ...
    return False

你可以关注here的对话

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