我为我的实体使用attrs包,它在大多数情况下工作得很好。我遇到的一个问题是在定义getter时对于属性(通常在纯python中@property)是goto
对于setterattrs
有一个方便的参数on_setattr
,其工作方式如下:
@attr.s(kw_only=True)
class Customer:
name = attr.ib(type=str, on_setattr=[prevent_empty_string, other_validators_or_logics, ])
,它使我们从使用@name.setter
几乎在任何情况下(至少在我的经验)
但是,当我们在返回属性时有一些逻辑时,当然不能使用:
@property
def name(...
,因为它会覆盖属性名的原始定义。所以我想知道attrs
中是否有任何方法可以用于这种情况,或者如果没有,除了定义另一个具有不同名称的属性之外,还有什么其他解决方案,即
@property
def get_name(self):
return self.name # or whatever
更新一个解决方案是使用/重写__getattribute__
的attr来添加逻辑,如:
@attr.s(kw_only=True)
class Customer:
name = attr.ib(type=str, on_setattr=[prevent_empty_string, other_validators_or_logics, ])
def __getattribute__(self, name: str) -> Any:
if name == "name":
return self.__dict__["name"].upper()
return super().__getattribute__(name)
但最终,它会被大量的if/switch块污染,更重要的是会扰乱内置的__repr__
没有。到目前为止,假设对于您的用例,您将有一个私有属性并在其上定义一个属性。
如果你这样做:
@attr.define
class Customer:
_name: str = attr.field(on_setattr=[…])
@property
def name(self) -> str:
return self._name.upper()
@name.setter
def name(self, value: str) -> None:
self._name = value
你应该用更少的神奇元编程获得所有的好处。
注意:_name
的__init__
参数仍然是name
。