如何为带有slots=True的dataclass定义__dict__属性?
如何为带有slots=True的dataclass定义__dict__属性?
这个问题我之前也碰到过,咱们先理清楚为啥你原来的代码会报错,再给出可行的解决方案~
首先看你提供的示例代码:
from dataclasses import dataclass @dataclass(slots=True) class Circle: radius:int = 2 @property def myslots(self): return self.__slots__ @property def __dict__(self): return self.__slots__ c = Circle() print(c.myslots) print(c.__dict__)
运行后会抛出AttributeError: 'Circle' object has no attribute '__dict__',原因很简单:当给dataclass设置slots=True且没有显式把__dict__加入slots列表时,Python不会为实例创建__dict__属性。而__dict__是Python的特殊属性,访问它时会优先查找实例本身的属性,找不到就直接报错,不会去调用我们定义的@property。
接下来给你两种解决方案:
方案一:换个属性名(推荐,保留slots的内存优势)
既然__dict__容易和内置逻辑冲突,我们可以换个更清晰的名字,比如to_dict,手动遍历slot中的属性,把它们转换成字典:
from dataclasses import dataclass @dataclass(slots=True) class Circle: radius:int = 2 @property def myslots(self): return self.__slots__ @property def to_dict(self): # 遍历所有slot属性,生成对应的键值对字典 return {slot: getattr(self, slot) for slot in self.__slots__} c = Circle() print(c.myslots) # 输出 ('radius',) print(c.to_dict) # 输出 {'radius': 2}
方案二:显式将__dict__加入slots(适合必须用__dict__的场景)
如果你因为某些需求一定要用__dict__这个名字,可以在slots列表里显式添加它,这样Python会为实例创建__dict__属性,之后我们就能用@property覆盖它的行为了:
from dataclasses import dataclass @dataclass(slots=True) class Circle: radius:int = 2 # 显式把__dict__加入slots __slots__ = ('radius', '__dict__') @property def myslots(self): return self.__slots__ @property def __dict__(self): # 自定义返回内容,排除__dict__本身 return {slot: getattr(self, slot) for slot in self.__slots__ if slot != '__dict__'} c = Circle() print(c.myslots) # 输出 ('radius', '__dict__') print(c.__dict__) # 输出 {'radius': 2}
不过要注意,这种方式会让实例拥有真正的__dict__,会损失slots原本节省内存的优势,所以除非有特殊需求,更推荐第一种方案。
备注:内容来源于stack exchange,提问作者robertspierre
相关产品推荐
相关产品推荐

