为什么 python 中的显式协议不需要 @runtimechecks 的属性实现,但隐式协议需要?

Why do explicit protocols in python not require attribute implementation for @runtimechecks, but implicit protocols do?

如果协议是用必需的属性实现的,即 name

@runtime_checkable
class DuckProtocol(Protocol):
    """Protocol for a duck"""
    name: str
    @abstractmethod
    def quack(self):
        raise NotImplementedError

如果没有 name 属性,对隐式子类型的 isinstance 运行时检查将失败,但显式子类型不会:

class Duck1(DuckProtocol):
    def quack(self):
        print('quack')
        
class Duck2:
    def quack(self):
        print('quack')

class Duck3:
    def __init__(self):
        self.name = 'duck3'
    def quack(self):
        print('quack')

print(isinstance(Duck1(), DuckProtocol))
print(isinstance(Duck2(), DuckProtocol))
print(isinstance(Duck3(), DuckProtocol))

输出:

True
False
True

为什么这个属性检查不扩展到显式子类型?

Duck1() 不遵循 DuckProtocol 协议定义的规范,但它仍然是协议 class 的实例,通常意义上的对象是 classes:它的类型是 Duck1,它是 DuckProtocol class 的子 class。根据 isinstance 的默认规则,这使得 Duck1() 成为 DuckProtocol.

的实例

运行时可检查协议定义了它们自己的 isinstance 逻辑(通过实施 __instancecheck__), but if that logic doesn't decide the object is an instance of the protocol, it ends by delegating to super().__instancecheck__ instead of returning False. After a whole bunch more indirection and delegation, we eventually end up in _abc._abc_subclasscheck, which checks for concrete subclasses 作为其处理的第 4 步,并且此检查 returns True.