Re: [Python-ideas] A user story concerning things knowing their own names

[+python-ideas] On Thu, Mar 17, 2011 at 10:12 PM, Ian Bicking <ianb@colorstudy.com> wrote:
Did you have any opinion on __addtoclass__? It seemed to me to address most of the use cases (even Greg's as far as I understood it).
[Reminder: Ian's proposal is to call attr.__addtoclass__(cls, name) for all attributes of the class that have the method, at class construction time.] You know, somehow I missed that when skimming. :-( It nicely encapsulates the main reason for having a metaclass in many of these cases. There's another pattern where all class attributes that have a certain property are also collected in a per-class datastructure, and at that point we're back to the custom metaclass; but standardizing on __addtoclass__ with the proposed signature would be a first step. We could either have a standard metaclass that does this, or we could just make it part of 'type' (the default metaclass) and be done with it. -- --Guido van Rossum (python.org/~guido)

Guido van Rossum wrote:
There's another pattern where all class attributes that have a certain property are also collected in a per-class datastructure,
I think __addtoclass__ could cover those as well, if you can arrange for the relevant objects to inherit from a class having an appropriate __addtoclass__ implementation. If that's not convenient, another approach would be to wrap them in something whose __addtoclass__ does the right thing and then unwraps itself. -- Greg

On Fri, Mar 18, 2011 at 9:37 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Guido van Rossum wrote:
There's another pattern where all class attributes that have a certain property are also collected in a per-class datastructure,
How do you put an attribute (such as __addtoclass__ ) on a name? Or are you proposing that the actual pattern be something more like: x=SpecialObj() And that normal initiation be handled either later, or as part of the SpecialObj initiation x=SpecialObj()=5 or x=SpecialObj(); x=5 or x=SpecialObj(value=5) Doing this for every name seems likely to be wasteful. Doing it only for certain initial values seems too magical. Doing it only for certain attributes -- there still needs to be a way to mark them, and I suppose we're back to either a decorator or a special assignment operator. @decorated_implies_an_object x=5 x:=5 What have I missed here? -jJ

On Fri, Mar 18, 2011 at 8:58 PM, Jim Jewett <jimjjewett@gmail.com> wrote:
What we're describing only applies to class variables; a top-level variable wouldn't be affected. Imagine for instance a column class (ORMish) that wants to know its name: class Column(object): def __init__(self, **kw): ... def __addtoclass__(self, name, cls): self.name = name return self Now if you do: class MyTable: username = Column() Then MyTable.username.name == 'username' If you wanted to be able to reuse values, like Greg wants, you could do: class Column(object): def __init__(self, kw): self.kw = kw ... def copy(self): return self.__class__(self.kw) def __addtoclass__(self, name, cls): new_obj = self.copy() new_obj.name = name return new_obj Or you could use several different classes (e.g., BoundColumn), or... well, there's many ways to skin a cat. Like descriptors, only objects that implement this new method would participate. It's not really like a decorator, it's much more like descriptors -- decorators like classmethod just happen to be descriptor factories. Ian

Ian Bicking wrote:
If you wanted to be able to reuse values, like Greg wants,
Actually I don't want to reuse values, that was someone else. For my use case it's fine to create a new descriptor for each use. -- Greg

On Fri, Mar 18, 2011 at 7:15 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
So, apologies if this has been brought up or rejected before, wouldn't a class decorator work for you? That is totally capable of calling x.__addtoclass__() (or whatever you want to call it -- it's now between the decorator and overridable_property) for each class attribute (really: for each value in the class __dict__) that has it, and doesn't seem to have the problems with combining unrelated metaclasses that you brought up: unrelated class decorators combine just fine (especially ones like this that mutate the class but still return the original class object). -- --Guido van Rossum (python.org/~guido)

Guido van Rossum wrote:
So, apologies if this has been brought up or rejected before, wouldn't a class decorator work for you?
It would work, although it would be a bit less than satisfying, because the property wouldn't be fully self-contained. Some of the plumbing would still be showing, albeit less obtrusively. -- Greg

On Mon, Mar 21, 2011 at 12:10 AM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:
If you forget the decorator (easy to do) the errors could be lots of ugly "<PropertyThatMustKnowName at 0x4928394> object has no attribute 'name'" -- and you could make the error slightly better, but not much because the PropertyThatMustKnowName doesn't get a chance to validate itself (since you didn't use the decorator and it can't really know that). Ian

On Sun, Mar 20, 2011 at 10:18 PM, Ian Bicking <ianb@colorstudy.com> wrote:
It would be easy enough to record the filename and line where the constructor was called, and report those in the error message. All in all it does sound like it could be an improvement over having to pass the name in redundantly, and it has the advantage that it works today. -- --Guido van Rossum (python.org/~guido)

Guido van Rossum wrote:
There's another pattern where all class attributes that have a certain property are also collected in a per-class datastructure,
I think __addtoclass__ could cover those as well, if you can arrange for the relevant objects to inherit from a class having an appropriate __addtoclass__ implementation. If that's not convenient, another approach would be to wrap them in something whose __addtoclass__ does the right thing and then unwraps itself. -- Greg

On Fri, Mar 18, 2011 at 9:37 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Guido van Rossum wrote:
There's another pattern where all class attributes that have a certain property are also collected in a per-class datastructure,
How do you put an attribute (such as __addtoclass__ ) on a name? Or are you proposing that the actual pattern be something more like: x=SpecialObj() And that normal initiation be handled either later, or as part of the SpecialObj initiation x=SpecialObj()=5 or x=SpecialObj(); x=5 or x=SpecialObj(value=5) Doing this for every name seems likely to be wasteful. Doing it only for certain initial values seems too magical. Doing it only for certain attributes -- there still needs to be a way to mark them, and I suppose we're back to either a decorator or a special assignment operator. @decorated_implies_an_object x=5 x:=5 What have I missed here? -jJ

On Fri, Mar 18, 2011 at 8:58 PM, Jim Jewett <jimjjewett@gmail.com> wrote:
What we're describing only applies to class variables; a top-level variable wouldn't be affected. Imagine for instance a column class (ORMish) that wants to know its name: class Column(object): def __init__(self, **kw): ... def __addtoclass__(self, name, cls): self.name = name return self Now if you do: class MyTable: username = Column() Then MyTable.username.name == 'username' If you wanted to be able to reuse values, like Greg wants, you could do: class Column(object): def __init__(self, kw): self.kw = kw ... def copy(self): return self.__class__(self.kw) def __addtoclass__(self, name, cls): new_obj = self.copy() new_obj.name = name return new_obj Or you could use several different classes (e.g., BoundColumn), or... well, there's many ways to skin a cat. Like descriptors, only objects that implement this new method would participate. It's not really like a decorator, it's much more like descriptors -- decorators like classmethod just happen to be descriptor factories. Ian

Ian Bicking wrote:
If you wanted to be able to reuse values, like Greg wants,
Actually I don't want to reuse values, that was someone else. For my use case it's fine to create a new descriptor for each use. -- Greg

On Fri, Mar 18, 2011 at 7:15 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
So, apologies if this has been brought up or rejected before, wouldn't a class decorator work for you? That is totally capable of calling x.__addtoclass__() (or whatever you want to call it -- it's now between the decorator and overridable_property) for each class attribute (really: for each value in the class __dict__) that has it, and doesn't seem to have the problems with combining unrelated metaclasses that you brought up: unrelated class decorators combine just fine (especially ones like this that mutate the class but still return the original class object). -- --Guido van Rossum (python.org/~guido)

Guido van Rossum wrote:
So, apologies if this has been brought up or rejected before, wouldn't a class decorator work for you?
It would work, although it would be a bit less than satisfying, because the property wouldn't be fully self-contained. Some of the plumbing would still be showing, albeit less obtrusively. -- Greg

On Mon, Mar 21, 2011 at 12:10 AM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:
If you forget the decorator (easy to do) the errors could be lots of ugly "<PropertyThatMustKnowName at 0x4928394> object has no attribute 'name'" -- and you could make the error slightly better, but not much because the PropertyThatMustKnowName doesn't get a chance to validate itself (since you didn't use the decorator and it can't really know that). Ian

On Sun, Mar 20, 2011 at 10:18 PM, Ian Bicking <ianb@colorstudy.com> wrote:
It would be easy enough to record the filename and line where the constructor was called, and report those in the error message. All in all it does sound like it could be an improvement over having to pass the name in redundantly, and it has the advantage that it works today. -- --Guido van Rossum (python.org/~guido)
participants (4)
-
Greg Ewing
-
Guido van Rossum
-
Ian Bicking
-
Jim Jewett