Python Data vs. Non-data Descriptors (original) (raw)

Summary: in this tutorial, you’ll learn the differences between data and non-data descriptors.

Descriptors have two types:

Both descriptor types can optionally implement the __set_name__ method. The __set_name__ method doesn’t affect the classification of the descriptors.

The descriptor types determine how Python resolves object’s attributes lookup.

Non-data descriptor #

If a class uses a non-data descriptor, Python will search the attribute in instance attributes first (instance.__dict__). If Python doesn’t find the attribute in the instance attributes, it’ll use the data descriptor.

Let’s take a look at the following example.

First, define a non-data descriptor class FileCount that has the __get__ method which returns the number of files in a folder:

class FileCount: def __get__(self, instance, owner): print('The __get__ was called') return len(os.listdir(instance.path))Code language: Python (python)

Second, define a Folder class that uses the FileCount descriptor:

`class Folder: count = FileCount()

def __init__(self, path):
    self.path = path`Code language: Python (python)

Third, create an instance of the Folder class and access the count attribute:

folder = Folder('/') print('file count: ', folder.count)Code language: Python (python)

Python called the __get__ descriptor:

The __get__ was called file count: 32Code language: Python (python)

After that, set the count attribute of the folder instance to 100 and access the count attribute:

folder.__dict__['count'] = 100 print('file count: ', folder.count)Code language: Python (python)

Output:

file count: 100Code language: Python (python)

In this example, Python can find the count attribute in the instance dictionary __dict__. Therefore, it does not use data descriptors.

Data descriptor #

When a class has a data descriptor, Python will look for an instance’s attribute in the data descriptor first. If Python doesn’t find the attribute, it’ll look for the attribute in the instance dictionary (__dict__). For example:

First, define a Coordinate descriptor class:

`class Coordinate: def get(self, instance, owner): print('The get was called')

def __set__(self, instance, value):
    print('The __set__ was called')`Code language: Python (python)

Second, define a Point class that uses the Coordinate descriptor:

class Point: x = Coordinate() y = Coordinate()Code language: Python (python)

Third, create a new instance of the Point class and assign a value to the x attribute of the p instance:

p = Point() p.x = 10Code language: Python (python)

Output:

The __set__ was calledCode language: Python (python)

Python called the __set__ method of the x descriptor.

Finally, access the x attribute of the p instance:

p.xCode language: Python (python)

Output:

The __get__ was calledCode language: Python (python)

Python called the __get__ method of the x descriptor.

Summary #

Was this tutorial helpful ?