-
-
Notifications
You must be signed in to change notification settings - Fork 382
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
init hooks #68
Comments
I think the problem is that many libraries are based on inheritance. Gtk-python, PyQt, Django... I think it would reduce too much the use cases of attr if inheritance was totally not supported. |
Re: |
@Insoleet I’m not sure what you’re trying to say; is there anything about this proposal contrary to that? |
I'm not sure, I would just like to be sure that you guys takes inheritance into account and not just don't care about it :) The |
Random idea time! What do y’all think about: import attr
class C:
x = attr.ib()
@attr.hooks.post_init
def i_dont_care_how_its_called(self):
# ... Positive:
Negative:
|
+1 I'd say just call them in order of definition within class... For On Aug 22, 2016 4:49 AM, "Hynek Schlawack" [email protected] wrote:
|
I like the cleanness of the decorator idea, although I'd alias it
What about |
MRO. The only right way to cooperatively call an overriden method is |
I very much like the idea of this hook decorator, though! I don't like typing underscores, so my suggestion for the spelling would be |
Regarding "if multiple hooks are registered" - my suggestion for the first iteration of this would be to just make registering a second hook into an immediate exception at registration time. If we come up with a non-confusing way to register multiple hooks, it's always fine to add it later. |
Just to clarify my gut feeling: usually when you have a class hierarchy, the first line in your Since
Of course, even in Java you can call |
Have you guys thought about using I've built a similar library (not nearly as impressive, but prior to this coming along), and that technique serves us very well |
For serialization and deserialization, the expected protocol for |
I don't have much context, so potentially I'm missing something We use |
There are a few variants of the pickle protocol that do call I may be wrong on some of the details above, it's been quite a while, but On Aug 23, 2016 12:44 AM, "Maximilian Roos" [email protected]
|
Yeah so any type of classic meta programming is out of the question. |
This isn't my battle, so I'll leave this here unless really needed. But I'd really encourage you guys to have a read up on how
Nope! It's just like
It would need to super up, in the same way that you'd need to super up if using
No meta programming here! Overall I would love to transition to this library, and you guys have done some amazing work... |
On Aug 23, 2016 10:01 AM, "Maximilian Roos" [email protected]
Likewise. Let's drop it. |
Ok looks like we got bogged down in discussing inheritance stuff, which is exactly what @glyph warned against in the OP. A suggestion:
|
Removing milestone, this bikeshed will take a while to pain. |
@hynek - Small PRs, small releases :) |
It sounds like we're converging on |
I feel there has to be the word hook somewhere. |
@hynek I specifically wanted to avoid the word "hook", not for brevity, but it sounds like jargon. The word "after" is very clear (this is "after init") and "hook" is something some users might not have heard of, and for the users who have heard of it, it's redundant. |
@hynek trust me, if I'm going for brevity, you'll know. |
(I am not strongly opposed though, if you really think it's more readable it's fine with me.) |
What's wrong with class methods? @attr.s
class Object:
id = attr.ib()
position = attr.ib(validator=instance_of(int))
@classmethod
def create(cls, *args, **kwargs):
obj = cls(*args, **kwargs)
obj.position = obj.position + 1
return obj
obj = Object.create(123, position=2)
print(obj.position) |
Because then the standard constructor is callable but gives an unitialized On Sep 20, 2016 9:03 AM, "Fabian Kochem" [email protected] wrote:
|
Sorry, I just searched for "class method", not for "classmethod". |
No worries, I wouldn't read the whole thread either. :-) |
Here's SO on how to find yourself: http://stackoverflow.com/posts/9934299/revisions |
Let's step back and talk about the use cases:
In case 1 and 3, you might as well write
is not very different amount of typing, and has a clearer intent than this:
In case 2, any of the post-init hook solution mentioned above would work. And there is no issue with inheritance in that case. |
It's a potentially wrong intent, though. |
My thinking is by the time you write |
How about this. Kind of like
From the outside, |
Personally (and I suspect @hynek would agree) I find the idea of writing an |
Problem is that it's gonna need some way to signal that it's there (checking using getattr seems gross and not fitting the explicit design of attrs) which brings us back to the decorator solution... 🎠 |
Wouldn't |
Two ideas.
Subclassing and the custom |
A new painter appears! :D At this I think the question is whether we go:
I’m not sure what you mean by subclassing/custom super, because it’s all just about people wanting to subclass non-attrs classes and call super on them. It’s not meant as a mean to solve the problem here but a goal to enable. :) ThoughtsMagic Dunder
Decorator
So personally, I feel like a decorator would be more attrs-style because it’s more explicit and less error prone and plays well WRT to intra-attrs subclassing. I’d love thoughts on these two approaches. I guess if someone offered me a good PR for Lukasz’s 1. point I’d begrudgingly merge it. |
Well, a counter-argument to the typos in the name is that you can also mistype init, str, etc. and they will all happily do nothing. As for allowing multiple hooks with a decorator, then you run into issues with ordering. I'd rather only have to override one hook, possibly calling super() inside it. While this also has problems, it's less custom and magical than decorators. |
Yes but what about subclassing? What if someone relies on the hook being run to initialize an attribute? :-/ |
If you go with …reads through the whole previous discussion to make sure nobody else has raised this already… The problem with Let me posit such a solution, actually. Instead of trying to make Making |
After typing that all out and swapping the whole previous conversation into my brain again, I'm coming down more and more in favor of just a |
attrs initializes parents attrs class's attributes without ever calling super(). It just inspects the list of arguments, including the parents. So should pre-init and post-init follow the same rule as attrs' Should attr's generated init be like this:
Or should it be like this:
And the defined |
@mathieulongtin Okay so I just re-invented what it already does? :) (I have very lightly used inheritance with attrs once or twice, but never had a complex hierarchy and never inherited anything that required an |
Honestly, the more I think about it, the more I think that with this hook |
Hm how do you mean “other than |
Fixed in #111! 🚲 🏠 🌈 |
Semi-related: Here's a ticket (and comment) describing how to run all post-init hooks in a full class inheritance hierarchy with attrs: |
PS, for anyone as confused as I was about the end of the OP's post:
^ That comment is a joke. Class inheritance is not deprecated in python and is not being removed. In fact the python docs at https://docs.python.org/3/tutorial/classes.html#inheritance say "Python classes provide all the standard features of Object Oriented Programming: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, and a method can call the method of a base class with the same name." and "Of course, a language feature would not be worthy of the name "class" without supporting inheritance." Python is not removing class inheritance. |
The joke is only funny because it should, though. Looks like we missed the boat for 3.7 but there's always Python 4! |
Sometimes I want to write an
attr.s
class that has some behavior in its constructor. Particularly:open
something, for example) (sorry)Arguably, many of these things could be expressed as a function, but some of them involve preserving valid structural relationships between the object and its dependencies, so I'd really prefer to be able to use
__init__
in some cases.I know, I can write my own
__init__
. I know! But if I do that, I give up not just on the convenience ofattr.s
writing the__init__
for me, but also the useful behavior ofattr.s
: i.e. validators, default factories.All of my use-cases here would be easily accomplished with either a pre-
__init__
and post-__init__
hook. Most of the ones I'm actually interested in would all be achievable with a post-__init__
hook; I think pre-__init__
might be pointless given the availability ofconvert=
.This has been discussed already, but some of the other issues (#33 #24 #38 #38 #58) which have raised the possibility of a post-
__init__
hook have been somewhat conflated with better support for inheritance. As we all know, inheritance is deprecated and will be removed in python 3.7 so we don't need to focus on that.The text was updated successfully, but these errors were encountered: