2

I was reading this thing from the internet

For objects, the machinery is in object.__getattribute__which transforms b.x into type(b).__dict__['x'].__get__(b, type(b)).

The implementation works through a precedence chain that gives data descriptors priority over instance variables, and instance variables priority over non-data descriptors, and assigns lowest priority to getattr if provided.

I didn't understand what does it mean by "giving data descriptor priority over instance variable" and "instance variables priority over non-data descriptors"

Can anyone give me example how this practically works i want to see what thing has priorty in code

Blender
  • 289,723
  • 53
  • 439
  • 496
user196264097
  • 877
  • 2
  • 13
  • 23
  • look at the example code in [@blckknght's answer](http://stackoverflow.com/a/14787522/4279) to [the related question](http://stackoverflow.com/q/14787334/4279). – jfs Feb 10 '13 at 11:32
  • I realise this is an old question but see also https://docs.python.org/3/howto/descriptor.html#descriptor-protocol especially if new to data/non-data descriptors – sparrowt Jun 02 '23 at 10:17

1 Answers1

6

Each object has a dictionary of attributes that contains it's variables and functions. Referring to these dictionaries:

If an instance’s dictionary has an entry with the same name as a data descriptor,    
the data descriptor takes precedence. If an instance’s dictionary has an entry with
the same name as a non-data descriptor, the dictionary entry takes precedence.

This is what they were talking about.

To show this:

#data descriptor
class A(object):
   def __get__(self, obj, type):
       print "hello from get A"
   def __set__(self, obj, val):
       print "hello from set A"
#non data descriptor
class B(object):
   def __get__(self, obj, type):
       print "hello from get B"

class C(object):
   #our data descriptor
   a = A()
   #our non data descriptor
   b = B()

>>> c = C()
>>> c.a
hello from get A
>>> c.b
hello from get B
>>> c.a = 0
hello from set A
>>> c.a          #notice after reassignment, A.__get__ is still called
hello from set A
>>> c.b = 0     #instance variable with the same name as the non data-descriptor
>>> c.b         #notice how B.__get__ isn't called anymore
0

Basically it is saying that when __get__ and __set__ are user defined for an object (data descriptor), they will be called instead of the default methods. If only __get__ is user defined for an object(non-data descriptor), the instance can reassign am instance variable.

So when calling g.x = 0: if x is a data descriptor then x's user-defined __set__ method is called, when x is an instance variable, or non-data descriptor the default behavior is called.

With a data descriptor, the class is controlling all access and modification to the variables. All access to variables of your data descriptor type will go through __get__ and __set__. So c.a = 0 calls A.__set__ and c.a is changed how the class defined it. There is no way to create an instance variable 'c.a' that is not of the type A.

With a non data descriptor, the class only controls access, so when c.b = 0 is called, since __set__ isn't defined, a new instance variable is made(the default behavior). There is no user-defined behavior on setting the variable, so you can create an instance variable with the same name, without the __get__ behavior.

The precedence they are talking about is the dynamics of the two. A data descriptor will always call __get__ and __set__, and so an instance variable can't be created with the same name. A non data descriptor will only call __get__ until an instance variable with the same name is created.

Stephen
  • 2,365
  • 17
  • 21
  • Again i am unclear. you said that If `x is data descriptor` so it means if x hasn `__get__` and `__set__` defined. right? so it means x will always be a class because i can only define methods in class. If `x` is instance variable then how can i define methods like `__get__` inside a variable. This is confusing me – user196264097 Feb 10 '13 at 14:28
  • Yes, the definition of a data descriptor is that it has `__get__` and `__set__` defined. A non-data descriptor only has `__get__` defined. An instance variable can be an object of a class, so something like `c.a = MyClass()`. It's more about how a data descriptor user-defines modification with `__set__`, and how a non data descriptor doesn't user-define modification. I edited to try to improve clarity. – Stephen Feb 10 '13 at 19:20
  • note: objects that have class with `__slots__` attribute don't have a dictionary of attributes. – jfs Feb 11 '13 at 02:40