@runtime_checkable 装饰器
@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 = name
class 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
,你可以实现灵活的运行时接口检查,适用于插件系统、动态验证等场景。