I use attrs package for my entities and it works like a charm in most cases. An issue I faced is in defining getter for attributes (generally in pure python @property is the goto)
for setter attrs
has a handy parameter on_setattr
that works like:
@attr.s(kw_only=True)
class Customer:
name = attr.ib(type=str, on_setattr=[prevent_empty_string, other_validators_or_logics, ])
and it relieves us from using @name.setter
virtually in any scenario (at least in my experience)
but still, when we have some logic in times of returning the attributes, of course, we cannot use:
@property
def name(...
because it will override the original definition of our attrs' name. So I want to know if there is any way builtin in attrs
for such a case or if not what are other solutions besides defining another attribute with a different name i.e.
@property
def get_name(self):
return self.name # or whatever
Update
A solution would be using/overriding __getattribute__
of attr to add logic something like:
@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)
but eventually, it gets polluted with a lot of if/switch blocks and more importantly will mess with builtin __repr__
CodePudding user response:
There is not…so far the assumption was that for your use-case you'd have a private attribute and define a property on top of it.
If you do something like:
@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
you should get all the upsides with less magic metaprogramming.
N.B. the __init__
argument of _name
will still be name
.