我正在尝试对魔术方法和普通方法修复一些方法注释。例如,我有一些情况,例如:
```
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
装饰器重写方法,并且需要尊重继承的顺序。正确吗?
如果我的假设正确,那么在哪里可以找到父类的确切签名?
答案 0 :(得分:0)
在mypy
上提问后,答案是:
子类化
typing.Mapping[str, str]
,我假设该函数 包含中的自变量键的签名应与 通用类型?
包含不是通用方法-它定义为具有类型签名包含((自我,密钥:对象)-> bool)。您可以在typeshed上进行检查。之所以这样定义包含,是因为在{“ foo”:“ bar”}中执行类似1的操作在技术上是合法的。
将def 包含(自身,密钥)子类化到def 包含(自身,密钥: 在任何情况下,str)都是更具体的。更具体的子类型不 违反利斯科夫,不是吗?
覆盖函数时,可以使参数类型更通用,而返回类型更具体。也就是说,参数类型应该是协变的,而返回类型应该是协变的。
如果我们不遵守规则,最终可能会在代码中引入错误。例如:
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的一个实例传递给测试最终导致引入了错误。
基本上,如果我对Any
方法的key
使用__contains__
是正确的,并且mypy
不会抱怨:
def __contains__(self, key: typing.Any) -> bool:
...
return False
您可以关注对话here