如何创建可轻松实例化的仅含属性的派生协议类?
如何创建可轻松实例化的仅含属性的派生协议类?
这个场景我太熟了!直接给Protocol套dataclass确实会踩坑,毕竟Protocol的设计初衷就是做类型检查用的,压根不是给你实例化的。不过不用重新写一遍属性,有两个简单的办法能搞定:
方法一:用dataclasses.make_dataclass快速生成
make_dataclass可以直接从Protocol的注解里提取字段,自动帮你生成符合要求的数据类,完全不用手动重复属性定义:
import dataclasses from typing import Protocol class P(Protocol): val: int desc: str # 多加个属性测试兼容性 # 从Protocol的__annotations__里提取所有字段 PInst = dataclasses.make_dataclass( 'PInst', fields=[(field_name, field_type) for field_name, field_type in P.__annotations__.items()] ) # 现在可以正常实例化,而且自动符合P协议 test_obj = PInst(val=4, desc="测试实例") print(test_obj.val) # 输出 4 print(isinstance(test_obj, P)) # 输出 True,类型检查也能通过
这个方法最省心,生成的类自带dataclass的所有特性(比如自动生成的__init__、__repr__这些),完美适配原Protocol的属性要求。
方法二:自定义实现类+复用注解
如果你想给实例类加一些自定义逻辑(比如专属方法、自定义__repr__),可以先建一个空类,把Protocol的注解直接赋值给它,再按需装饰:
import dataclasses from typing import Protocol class P(Protocol): val: int # 自定义实现类,复用P的注解 class PImpl: __annotations__ = P.__annotations__ # 加个自定义的打印方法 def __str__(self): return f"P实例,val值为: {self.val}" # 套上dataclass,让它拥有自动生成的初始化方法 PImpl = dataclasses.dataclass(PImpl) # 正常实例化 obj = PImpl(val=10) print(obj) # 输出 "P实例,val值为: 10" print(isinstance(obj, P)) # 输出 True
这种方式灵活性更高,既能复用Protocol的属性定义,又能给类加自己的功能,完全不用重复写属性。
为啥直接dataclasses.dataclass(P)不行?
因为Protocol是typing模块里的特殊类,它的元类和普通类不一样,就算用dataclass装饰,Python还是会识别它是Protocol的子类,而Protocol本身就被设计成不能实例化的,所以才会报那个TypeError。
备注:内容来源于stack exchange,提问作者Jan Šimbera
相关产品推荐
相关产品推荐

