Re: [Tutor] @property for old style classes vs new style classes
On Thu, Sep 15, 2016 at 9:48 PM, monik...@netzero.net wrote: > But why var is in class __dict__? > Does @property make it a class attribute? An instance of `property` is a data descriptor, i.e. it implements the __get__, __set__, and __delete__ methods of the descriptor protocol. A non-data descriptor only implements __get__. Descriptors are fundamental to the way attribute lookup works in Python. See the descriptor howto guide: https://docs.python.org/3/howto/descriptor.html The above document paints a picture of attribute access that's not really accurate at times. Also, the example code that attempts to demonstrate type.__getattribute__ in terms of object.__getattribute__ is wrong. (It fails to search the __mro__ of the class, only the metaclass. Also, what it's trying to do is fundamentally impossible. You can't know whether object.__getattribute___ already evaluated a descriptor that it found in the metaclass.) Here's an overview of how object.__getattribute__ works: * If a data descriptor is found in the class, call its __get__ method, passing it the instance and the class, and return the result. * Else if the instance has a dict and the name is found in it, return the value from the instance dict. * Else if a non-data descriptor is found in the class, call its __get__ method, passing it the instance and the class, and return the result. * Else if a non-descriptor is found in the class, return it. * Else raise AttributeError. A class lookup searches the dicts of each class in the __mro__, stopping on the first hit. Also, a type can define a __getattr__ fallback method, in which case the AttributeError raised by __getattribute__ is ignored. For type.__getattribute__, the class object in this case is handled as an instance of the metaclass. The main difference compared to object.__getattribute__ is in the second step, since the instance in this case is a class. Instead of searching just the class dict, it searches the dicts of each class in the __mro__. Also, if it finds a descriptor in the class __mro__, it calls its __get__ method, passing None for the instance. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
I figured out why you have var in instance __dict__. It was after you added it. But why var is in class __dict__? Does @property make it a class attribute? Thank you Monika -- Original Message -- From: Steven D'Aprano To: tutor@python.org Subject: Re: [Tutor] @property for old style classes vs new style classes Date: Fri, 16 Sep 2016 02:57:12 +1000 On Thu, Sep 15, 2016 at 04:40:22AM +, monik...@netzero.net wrote: > Could somebody please explain what is going on for old style classes for the > below code: The important part is that the descriptor protocol doesn't get used for old style classes. If that statement means something to you, that's great, otherwise please ask. So in an old-style class: > class GetSet(): > > def __init__(self, value): > self.attrval = value > > @property > def var(self): > print "getting the var attribute" > return self.attrval > @var.setter > def var(self,value): > print "setting the var attribute" > self.attrval = value At this point, you have a class GetSet, with a class attribute: GetSet.var which is a property object. Now let's make an instance: > me = GetSet(5) > me.var = 1000 At this point, the instance now has an instance attribute: me.var which is the int 1000. So there are now TWO attributes called "me", living in different scopes: me.__dict__['var'] = 1000 # in the instance GetSet.__dict__['var'] = property object Remember that attribute look-ups normally look in the instance __dict__ before the class __dict__. > print me.var > del me.var > print me.var The first print looks for 'var' in the instance, finds it, and prints 1000. Then the del command looks for 'var' in the instance, finds it, and deletes it. Then finally the second print looks for 'var' in the instance, *doesn't* find it there (because it has been deleted), so it looks in the class, and finds GetSet.__dict__['var'] which is a property object. At this point, things get a bit mysterious. According to the documentation, Python ought to print something like: since the descriptor protocol doesn't run for old-style classes. But apparently it does *partly* run, because the property object's __get__ method is invoked, which calls the getter method that you defined. > Output: > 1000 > getting the var attribute > 5 So there is a part mystery here. As far as I can tell, the documentation suggests that the output should be: 1000 rather than what you got. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor 15 Actors Who Are Gay - No. 12 Will Shock Women trendytribune.com http://thirdpartyoffers.netzero.net/TGL3241/57db177b8815a177b1d3dst03duc ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
For both old and new classes I have var only in GetSet class, but not in instance me. Why? print me.__dict__ print GetSet.__dict__ {'attrval': 5} {'__weakref__': , '__doc__': None, '__module__': '__main__', '__init__': , '__dict__': , 'var': } >>> Thank you very much Monika -- Original Message ------ From: Steven D'Aprano To: tutor@python.org Subject: Re: [Tutor] @property for old style classes vs new style classes Date: Fri, 16 Sep 2016 02:57:12 +1000 On Thu, Sep 15, 2016 at 04:40:22AM +, monik...@netzero.net wrote: > Could somebody please explain what is going on for old style classes for the > below code: The important part is that the descriptor protocol doesn't get used for old style classes. If that statement means something to you, that's great, otherwise please ask. So in an old-style class: > class GetSet(): > > def __init__(self, value): > self.attrval = value > > @property > def var(self): > print "getting the var attribute" > return self.attrval > @var.setter > def var(self,value): > print "setting the var attribute" > self.attrval = value At this point, you have a class GetSet, with a class attribute: GetSet.var which is a property object. Now let's make an instance: > me = GetSet(5) > me.var = 1000 At this point, the instance now has an instance attribute: me.var which is the int 1000. So there are now TWO attributes called "me", living in different scopes: me.__dict__['var'] = 1000 # in the instance GetSet.__dict__['var'] = property object Remember that attribute look-ups normally look in the instance __dict__ before the class __dict__. > print me.var > del me.var > print me.var The first print looks for 'var' in the instance, finds it, and prints 1000. Then the del command looks for 'var' in the instance, finds it, and deletes it. Then finally the second print looks for 'var' in the instance, *doesn't* find it there (because it has been deleted), so it looks in the class, and finds GetSet.__dict__['var'] which is a property object. At this point, things get a bit mysterious. According to the documentation, Python ought to print something like: since the descriptor protocol doesn't run for old-style classes. But apparently it does *partly* run, because the property object's __get__ method is invoked, which calls the getter method that you defined. > Output: > 1000 > getting the var attribute > 5 So there is a part mystery here. As far as I can tell, the documentation suggests that the output should be: 1000 rather than what you got. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor Do This Before Bed Tonight to Burn Belly Flab All Night Long Flat Belly Overnight http://thirdpartyoffers.netzero.net/TGL3241/57db0db4a9dedb31f3bst04duc ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
Thank you both for your explanations but they were too difficult for me to understand. What is descriptor protocol? Can you please explain? I checked for var in both instance and class __dict__ but it was only in class, not in the instance. I checked for it after I instantiated me, before deletion. So now the post explaining it to me does not make a full sense. So it seem to me that the class on udemy did not explain very well how this @property works (they talked only about new classes). Now after reading the posts several times I feel I understand less how it works. Could somebody please explain how @property works in new classes? What is going on behind the scenes? And then how in comparison with old classes? I will reread the posts again and maybe I will understand it better. Please explain in simple English. :) Thank you very much Monika -- Original Message -- From: Steven D'Aprano To: tutor@python.org Subject: Re: [Tutor] @property for old style classes vs new style classes Date: Fri, 16 Sep 2016 02:57:12 +1000 On Thu, Sep 15, 2016 at 04:40:22AM +, monik...@netzero.net wrote: > Could somebody please explain what is going on for old style classes for the > below code: The important part is that the descriptor protocol doesn't get used for old style classes. If that statement means something to you, that's great, otherwise please ask. So in an old-style class: > class GetSet(): > > def __init__(self, value): > self.attrval = value > > @property > def var(self): > print "getting the var attribute" > return self.attrval > @var.setter > def var(self,value): > print "setting the var attribute" > self.attrval = value At this point, you have a class GetSet, with a class attribute: GetSet.var which is a property object. Now let's make an instance: > me = GetSet(5) > me.var = 1000 At this point, the instance now has an instance attribute: me.var which is the int 1000. So there are now TWO attributes called "me", living in different scopes: me.__dict__['var'] = 1000 # in the instance GetSet.__dict__['var'] = property object Remember that attribute look-ups normally look in the instance __dict__ before the class __dict__. > print me.var > del me.var > print me.var The first print looks for 'var' in the instance, finds it, and prints 1000. Then the del command looks for 'var' in the instance, finds it, and deletes it. Then finally the second print looks for 'var' in the instance, *doesn't* find it there (because it has been deleted), so it looks in the class, and finds GetSet.__dict__['var'] which is a property object. At this point, things get a bit mysterious. According to the documentation, Python ought to print something like: since the descriptor protocol doesn't run for old-style classes. But apparently it does *partly* run, because the property object's __get__ method is invoked, which calls the getter method that you defined. > Output: > 1000 > getting the var attribute > 5 So there is a part mystery here. As far as I can tell, the documentation suggests that the output should be: 1000 rather than what you got. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor Do This Before Bed Tonight to Burn Belly Flab All Night Long Flat Belly Overnight http://thirdpartyoffers.netzero.net/TGL3241/57db10cd7d30310cd7bb9st01duc ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
On Thu, Sep 15, 2016 at 04:40:22AM +, monik...@netzero.net wrote: > Could somebody please explain what is going on for old style classes for the > below code: The important part is that the descriptor protocol doesn't get used for old style classes. If that statement means something to you, that's great, otherwise please ask. So in an old-style class: > class GetSet(): > > def __init__(self, value): > self.attrval = value > > @property > def var(self): > print "getting the var attribute" > return self.attrval > @var.setter > def var(self,value): > print "setting the var attribute" > self.attrval = value At this point, you have a class GetSet, with a class attribute: GetSet.var which is a property object. Now let's make an instance: > me = GetSet(5) > me.var = 1000 At this point, the instance now has an instance attribute: me.var which is the int 1000. So there are now TWO attributes called "me", living in different scopes: me.__dict__['var'] = 1000 # in the instance GetSet.__dict__['var'] = property object Remember that attribute look-ups normally look in the instance __dict__ before the class __dict__. > print me.var > del me.var > print me.var The first print looks for 'var' in the instance, finds it, and prints 1000. Then the del command looks for 'var' in the instance, finds it, and deletes it. Then finally the second print looks for 'var' in the instance, *doesn't* find it there (because it has been deleted), so it looks in the class, and finds GetSet.__dict__['var'] which is a property object. At this point, things get a bit mysterious. According to the documentation, Python ought to print something like: since the descriptor protocol doesn't run for old-style classes. But apparently it does *partly* run, because the property object's __get__ method is invoked, which calls the getter method that you defined. > Output: > 1000 > getting the var attribute > 5 So there is a part mystery here. As far as I can tell, the documentation suggests that the output should be: 1000 rather than what you got. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
On Thu, Sep 15, 2016 at 02:08:12PM +, eryk sun wrote: > Getting attributes also prefers the instance dict. However, to support > bound methods (e.g. __init__), it falls back on a class lookup and > calls the descriptor __get__ method if defined. Is that documented anywhere? When was it introduced? Because I can see that in Python 2.4 and higher, function objects have a __get__, and old-style classes appear to call __get__ methods. But going back to Python 1.5 function objects DON'T have a __get__ and attribute lookup ignores __get__ even if designed. >>> class MyDescriptor: ... def __get__(self): ... print "calling descriptor __get__" ... return lambda self: "the getter" ... >>> class X: ... desc = MyDescriptor() ... >>> X.desc <__main__.MyDescriptor instance at 82d1940> Some time between Python 1.5 and 2.4, the behaviour of old-style classes was changed to *half* support the descriptor protocol. As far as I can see, that's not mentioned in the Descriptor HowTo guide: https://docs.python.org/2/howto/descriptor.html and it contradicts the comment here: https://docs.python.org/2/reference/datamodel.html#invoking-descriptors Quote: Note that descriptors are only invoked for new style objects or classes (ones that subclass object() or type()). -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] @property for old style classes vs new style classes
On Thu, Sep 15, 2016 at 4:40 AM, monik...@netzero.net wrote: > class GetSet(): > > def __init__(self, value): > self.attrval = value > > @property > def var(self): > print "getting the var attribute" > return self.attrval > @var.setter > def var(self,value): > print "setting the var attribute" > self.attrval = value > > @var.deleter > def var(self): > print "deleting the var attribute" > self.attrval = None > > me = GetSet(5) > me.var = 1000 A classic instance has both a type (`instance`) and a __class__ (e.g. GetSet). The type defines how getting, setting, and deleting attributes works, and the hard-coded classic behavior for calling the class __getattr__, __setattr__, and __delattr__ methods. If the class doesn't define __setattr__ and __delattr__, the instance type sets and deletes attributes directly in the instance dict. Unlike new-style classes, a data descriptor defined by the class gets ignored here. Getting attributes also prefers the instance dict. However, to support bound methods (e.g. __init__), it falls back on a class lookup and calls the descriptor __get__ method if defined. Unintentionally, it happens that this partially supports the property descriptor. But since there's no data descriptor support, it's only useful for read-only properties. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] @property for old style classes vs new style classes
Hi: Im studying @property, @var.setter and @var.deleter. I understand how they work in new style classes. Even though I do not use old style classes it would be interesting to understand what is going on behind the scenes. I can try to make assumptions but I do not want to because they might be incorrect. Could somebody please explain what is going on for old style classes for the below code: class GetSet(): def __init__(self, value): self.attrval = value @property def var(self): print "getting the var attribute" return self.attrval @var.setter def var(self,value): print "setting the var attribute" self.attrval = value @var.deleter def var(self): print "deleting the var attribute" self.attrval = None me = GetSet(5) me.var = 1000 print me.var del me.var print me.var Output: 1000 getting the var attribute 5 >>> Same code but with new style classes (this one I understand): class GetSet(object): def __init__(self, value): self.attrval = value @property def var(self): print ("getting the var attribute") return self.attrval @var.setter def var(self,value): print ("setting the var attribute") self.attrval = value @var.deleter def var(self): print ("deleting the var attribute") self.attrval = None me = GetSet(5) me.var = 1000 print (me.var) del me.var print (me.var) Output: setting the var attribute getting the var attribute 1000 deleting the var attribute getting the var attribute None Thank you very much Monika Unlock Visions (Sponsored by Content.Ad) 1 Odd Method 'Restores' Your 20/20 Vision. Try This http://thirdpartyoffers.netzero.net/TGL3241/57da2673b610726731820st03duc ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor