如何在Python Dataclass中利用列表动态设置对象属性?
用Python Dataclass简化重复属性定义与初始化
原代码的冗余问题
原代码中,normal、normalizedNormal、tangent、normalizedTangent这类属性的定义和初始化逻辑大量重复,新增属性时需要修改多处代码:
from dataclasses import dataclass, field @dataclass class Locator: locator_attr: str transform: str = field(init=False) position: tuple = field(init=False) point_on_curve: str = field(init=False) normal_attr: str = field(init=False) normal: tuple = field(init=False) normalizedNormal_attr: str = field(init=False) normalizedNormal: tuple = field(init=False) tangent_attr: str = field(init=False) tangent: tuple = field(init=False) normalizedTangent_attr: str = field(init=False) normalizedTangent: tuple = field(init=False) def __post_init__(self) -> None: self.transform = cmds.listConnections(f"{self.locator_attr}.locatorTransform")[0] self.position = cmds.xform(self.transform, q=True, t=True, ws=True) self.point_on_curve = cmds.listConnections(f"{self.locator_attr}.pointOnCurve")[0] self.normal_attr = f"{self.point_on_curve}.normal" self.normal = cmds.getAttr(f"{self.point_on_curve}.normal")[0] self.normalizedNormal_attr = f"{self.point_on_curve}.normalizedNormal" self.normalizedNormal = cmds.getAttr(f"{self.point_on_curve}.normalizedNormal")[0] self.tangent_attr = f"{self.point_on_curve}.tangent" self.tangent = cmds.getAttr(f"{self.point_on_curve}.tangent")[0] self.normalizedTangent_attr = f"{self.point_on_curve}.normalizedTangent" self.normalizedTangent = cmds.getAttr(f"{self.point_on_curve}.normalizedTangent")[0]
尝试动态生成属性时的错误
尝试用列表动态生成属性时,因错误处理列表与dataclass字段的关系,触发两类报错:
- 若将列表设为
field对象,会抛出'Field' object is not iterable - 若直接用普通列表作为dataclass字段,会抛出
mutable default <class 'list'> for field _node_attrs is not allowed: use default_factory
尝试的错误代码:
from dataclasses import dataclass, field @dataclass class Locator: locator_attr: str transform: str = field(init=False) position: tuple = field(init=False) point_on_curve: str = field(init=False) _node_attrs:list = ['normal','normalizedNormal','tangent','normalizedTangent'] for _attrname in _node_attrs: globals()[f'{_attrname}_attr']: str = field(init=False) globals()[f'{_attrname}']: tuple = field(init=False) def __post_init__(self) -> None: self.transform = cmds.listConnections(f"{self.locator_attr}.locatorTransform")[0] self.position = cmds.xform(self.transform, q=True, t=True, ws=True) self.point_on_curve = cmds.listConnections(f"{self.locator_attr}.pointOnCurve")[ 0 ]
简洁解决方案
核心思路:将重复属性列表设为类的普通常量(非dataclass字段),避免触发可变默认值检查;同时在类定义阶段动态添加字段,在__post_init__中循环完成属性初始化。
from dataclasses import dataclass, field @dataclass class Locator: locator_attr: str transform: str = field(init=False) position: tuple = field(init=False) point_on_curve: str = field(init=False) # 类常量,不作为dataclass字段(用元组更安全,避免误修改) _NODE_ATTRS = ('normal', 'normalizedNormal', 'tangent', 'normalizedTangent') def __post_init__(self) -> None: self.transform = cmds.listConnections(f"{self.locator_attr}.locatorTransform")[0] self.position = cmds.xform(self.transform, q=True, t=True, ws=True) self.point_on_curve = cmds.listConnections(f"{self.locator_attr}.pointOnCurve")[0] # 批量初始化重复属性 for attr_name in self._NODE_ATTRS: full_attr_path = f"{self.point_on_curve}.{attr_name}" setattr(self, f"{attr_name}_attr", full_attr_path) setattr(self, attr_name, cmds.getAttr(full_attr_path)[0]) # 动态添加字段定义与类型注解 for attr_name in Locator._NODE_ATTRS: attr_attr_name = f"{attr_name}_attr" # 添加field配置 setattr(Locator, attr_attr_name, field(init=False)) setattr(Locator, attr_name, field(init=False)) # 添加类型注解 Locator.__annotations__[attr_attr_name] = str Locator.__annotations__[attr_name] = tuple
该方案的优势:
- 新增属性仅需修改
_NODE_ATTRS一处 - 完全消除重复代码逻辑
- 符合dataclass规范,无报错风险
内容的提问来源于stack exchange,提问作者Vitor Augusto Mariano Silva
相关产品推荐
相关产品推荐

