Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More convenient shorthand for derived attributes #310

Open
gabbard opened this issue Dec 6, 2017 · 7 comments
Open

More convenient shorthand for derived attributes #310

gabbard opened this issue Dec 6, 2017 · 7 comments
Labels

Comments

@gabbard
Copy link
Member

gabbard commented Dec 6, 2017

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
Copy link
Member Author

gabbard commented Dec 6, 2017

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 gabbard closed this as completed Dec 6, 2017
@gabbard
Copy link
Member Author

gabbard commented Dec 6, 2017

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 gabbard reopened this Dec 6, 2017
@wsanchez
Copy link

wsanchez commented Dec 7, 2017

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.

@hynek
Copy link
Member

hynek commented Dec 7, 2017

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

@gabbard
Copy link
Member Author

gabbard commented Dec 7, 2017

@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 gabbard changed the title Allow for derived attributes More convenient shorthand for derived attributes Jan 22, 2019
@gabbard
Copy link
Member Author

gabbard commented Mar 6, 2019

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
Copy link
Member Author

gabbard commented Mar 7, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants