@runtime_checkable
是 Python 的 typing
模块中的一个装饰器,用于结合 Protocol
类型,允许在运行时检查一个对象是否符合某个协议(Protocol)。它扩展了 isinstance()
和 issubclass()
的功能,使得基于结构子类型(structural subtyping)的类型检查在运行时成为可能。
基本用法
-
导入装饰器:
from typing import runtime_checkable, Protocol
-
定义协议:
使用Protocol
定义一个接口,并用@runtime_checkable
装饰它。协议中需要声明对象必须包含的方法或属性。@runtime_checkable class SupportsClose(Protocol):def close(self) -> None:...
-
实现类:
定义一个类,无需显式继承协议,只需实现协议中定义的方法/属性:class File:def close(self) -> None:print("File closed")class NetworkConnection:def disconnect(self) -> None:print("Disconnected")
-
运行时检查:
使用isinstance()
检查对象是否符合协议:file = File() conn = NetworkConnection()print(isinstance(file, SupportsClose)) # 输出 True print(isinstance(conn, SupportsClose)) # 输出 False
关键点
-
结构子类型检查:
@runtime_checkable
检查对象是否拥有协议中声明的所有方法和属性(按名称检查)。- 不关心继承关系,只要结构匹配即可。
-
仅检查存在性:
- 不会检查方法签名(参数类型、返回值类型等)。
- 例如,协议中的方法如果有参数,但实现的方法没有参数,检查仍会通过,但调用时可能出错。
-
性能注意:
- 运行时检查可能影响性能,谨慎在高频代码中使用。
示例:检查属性
from typing import Protocol, runtime_checkable@runtime_checkable
class HasName(Protocol):name: str # 检查是否存在 name 属性(类型不强制)class Person:def __init__(self, name: str):self.name = nameclass Dog:def __init__(self):self.name = "Buddy"class Car:def __init__(self, model: str):self.model = model # 属性名不匹配person = Person("Alice")
dog = Dog()
car = Car("Tesla")print(isinstance(person, HasName)) # True
print(isinstance(dog, HasName)) # True
print(isinstance(car, HasName)) # False
True
True
False
常见问题
-
为什么
isinstance
返回False
?- 确保协议被
@runtime_checkable
装饰。 - 检查对象是否确实实现了协议的所有方法和属性(名称一致)。
- 确保协议被
-
与
abc.ABC
的区别?abc.ABC
基于继承(名义子类型),要求显式继承。@runtime_checkable
基于结构子类型,无需继承。
通过 @runtime_checkable
,你可以实现灵活的运行时接口检查,适用于插件系统、动态验证等场景。