Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Examining the Lookup Chain

00:00 In previous lessons, you have learned that when using descriptors, you can apply your own magic when accessing an attribute using the dot notation. But how does that really work?

00:11 How do descriptors influence that behavior? Well, to understand that you need to know about the lookup chain.

00:18 Now, what is the lookup chain? Well, when an attribute is accessed via the dot notation, Python has some sort of a priority list of sources it goes through to retrieve the attribute value, and that priority list, that is the lookup chain.

00:34 Now, crucially, descriptors sit somewhere in this lookup chain. Now, to explain that a little bit better, I need to introduce to you three new concepts. Firstly, there are data descriptors.

00:48 Secondly, non-data descriptors. And thirdly, I need to talk to you about the __dict__ attribute.

00:56 Now to cover the first two,

00:59 you will remember the descriptor protocol with its four methods. Now, the __set_name__() method, the fourth one was optional, and it doesn’t actually feature in the definitions of data and non-data descriptors.

01:13 So we’ll park that one for now. But if you only use the __get__() method, then you are in fact implementing a non-data descriptor. If you are using the __set__() or __delete__() methods, then you are implementing a data descriptor.

01:31 And why does that matter? Well, as you will see in a minute, data descriptors have a higher priority in the lookup chain.

01:41 And the third new concept is this dict attribute or this __dict__ attribute. Now, what is this? Now, when you create a class in Python, then Python will automatically in the background create this non-public __dict__ attribute for you.

01:57 So it’s an attribute of your class and of your class instance. And the difference between the two will become important later when you look at the lookup chain in detail.

02:09 And as the name might suggest, this __dict__ attribute is in fact a dictionary. And the keys of this dictionary are the names of the attributes and methods of your class.

02:21 And the values of this dictionary are then the values of the attributes or the method objects.

02:30 So __dict__, in effect, represents a namespace.

02:34 Now you might remember earlier in the course we used vars() to investigate a Song class instance, and that then returned a dictionary.

02:44 You might remember “A Forest” by The Cure. And that is in fact that __dict__ attribute.

02:53 Now I appreciate I’ve gone through this rather quickly, so I’ll include a link to an excellent video tutorial that explains the __dict__ attribute in detail.

03:03 And I’ll also include a link to another video course that explains the use of underscores and double underscores, and therefore the difference between public and non-public objects in Python.

03:16 So with that new knowledge of data and non-data descriptors, and the namespace of your class and class instances, you are ready to look at the lookup chain in detail.

03:27 So this is this priority list. Firstly, Python will look at the __get__() method of a data descriptor. If it fails to find an attribute value there, it will look in the __dict__ attribute of your class instance.

03:42 And if it doesn’t find anything there, it will look at the __get__() method of your non-data descriptor. If it fails to find a value there, it will look in the __dict__ attribute of your class, not the class instance.

03:57 The class instance, that is step two. The class itself is step four. Now if it fails to find anything there, it will go up higher in the chain. It will look at the parent type of your object, and in particular in the __dict__ attribute of that object parent type.

04:15 And if it fails to find anything in the object parent type, it will then repeat step five for all parent types in the method resolution order of your object.

04:26 And if all that fails, then in the end you’ll get an AttributeError exception. Now the detail behind steps five and six is beyond the scope of this course.

04:38 The key point here is that firstly, descriptors are parts of this lookup chain, and that’s how you can use them to build your own magic. And secondly, data descriptors have a higher priority than non-data descriptors, and the written tutorial for which I also include a link, investigates this a little bit more.

05:00 So that’s it for the lookup chain. In the next lesson, you will summarize all the learnings from this course.

Become a Member to join the conversation.