attrs icon indicating copy to clipboard operation
attrs copied to clipboard

More convenient shorthand for derived attributes

Open gabbard opened this issue 7 years ago • 7 comments

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?

gabbard avatar Dec 06 '17 21:12 gabbard

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

gabbard avatar Dec 06 '17 22:12 gabbard

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.

gabbard avatar Dec 06 '17 22:12 gabbard

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.

wsanchez avatar Dec 07 '17 04:12 wsanchez

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. ¯\_(ツ)_/¯

hynek avatar Dec 07 '17 13:12 hynek

@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.

gabbard avatar Dec 07 '17 14:12 gabbard

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).

gabbard avatar Mar 06 '19 17:03 gabbard

After thinking more about this, there are several distinct but entangled issues here. I'll comment more when I have time (probably Monday)

gabbard avatar Mar 07 '19 03:03 gabbard