在 python 中,我可以缩小 class 的协议定义属性吗?

In python, can I narrow down protocol-defined properties of the class?

让我用一个例子来解释:

import typing as t
from dataclasses import dataclass

# describe our protocols
class ID(t.Protocol):
    "This protocol describes some kind of ID."
    def __hash__(self) -> int:
        raise NotImplementedError
    def __eq__(self, other) -> bool:
        raise NotImplementedError
    def __str__(self) -> str:
        raise NotImplementedError

class ObjectWithID(t.Protocol):
    "This protocol describes an object that has an ID."
    @property
    def id(self) -> ID:
        raise NotImplementedError

# now describe real classes
class MyID(ID):
    "Implementation of ID protocol"
    def __init__(self, val: int):
        self.value: int = val
    def __hash__(self) -> int:
        return self.value
    def __eq__(self, other) -> bool:
        return isinstance(other, MyID) and self.value == other.value
    def __str__(self) -> str:
        return str(self.value)

@dataclass
class MyObject(ObjectWithID):
    id: MyID # <<< THIS

现在,PyCharm 坚持认为 id 是 MyID 类型破坏了与 ObjectWithID 协议的兼容性。 然而,pylint 并不介意这一行。 我也不,因为从我的角度来看,任何正确的 MyObject 实例都将与 ObjectWithID 协议兼容。

谁是正确的?只抑制 PyCharm 中的警告对我来说安全吗?

我可以看到,如果存在 ID 的另一个实现,MyObject 将不会接受它,而 ObjectWithID 可以。但这真的是个问题吗?

由于MyID继承自ID,我认为pycharm是错误的,pylint是正确的。

mypy 在其文档中说明了以下关于子类的内容:

Any instance of a subclass is also compatible with all superclasses

https://mypy.readthedocs.io/en/stable/kinds_of_types.html#class-types