attrs
attrs copied to clipboard
More convenient shorthand for derived attributes
Resolving #165 allowed setting the default for an attribute based on other attributes using a decorator like this:
@attrs(frozen=True, slots=True)
class Foo:
bar = attr.ib()
moo = attr.ib()
@moo.default
def _init_moo(self):
return self.bar + 2
Many times in frozen classes we want to derive one attribute from another without giving the user the opportunity to override it. The Immutables library for Java provides for this via Value.Derived
: http://immutables.github.io/immutable.html#derived-attributes . Perhaps attrs could have a @field.derived
decorator which does the same thing?
Aha, this can be accomplished by:
@attrs(frozen=True, slots=True)
class Foo:
bar = attr.ib()
moo = attr.ib(init=False)
@moo.default
def _init_moo(self):
return self.bar + 2
Actually, I am going to re-open this, because what you really want is:
@attrs(frozen=True, slots=True)
class Foo:
bar = attr.ib()
moo = attr.ib(init=False, repr=False, hash=False, cmp=False)
@moo.default
def _init_moo(self):
return self.bar + 2
which is complicated and non-obvious enough that some syntactic sugar might be justified, since this is a frequent use case.
You could also make moo a property…
Unless you are using frozen=True
on the class, that arguably makes a bit more sense; it seems weird to not allow setting a value in __init__
but allow it to be set afterwards.
This all goes down that immutability and access restrictions in Python are just nothing else than theatre. Python has been designed with the “consenting adults” premise in mind and we’ll always run into weirdness when trying to add them by hand. ¯\_(ツ)_/¯
@wsanchez : ah, sorry, I just meant this in the context of frozen classes (that's almost all my team uses). I've updated the issue text and comments to reflect that.
A possible alternative approach would be to use a property with a memoizing decorator (since these derived fields are often expensive to compute), although I would guess that could have noticeable overhead over computing it once and storing it as a field.
It occurs to me that you probably want to exclude derived fields from serialization as well (since they don't determine the identity and content of the object), which would take this beyond being just syntactic sugar.
If we were willing to add this (with some TBD syntax and restricted to frozen classes), I would be happy to implement it (we have lots of cases of derived fields in our codebase).
After thinking more about this, there are several distinct but entangled issues here. I'll comment more when I have time (probably Monday)