Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Impara Data vs Non-Data Descriptors | What Descriptors Are
Python Descriptors Explained

Data vs Non-Data Descriptors

Scorri per mostrare il menu

Not all descriptors behave the same way in the attribute lookup chain. Python distinguishes between data descriptors and non-data descriptors based on which methods they define – and this distinction determines whether a descriptor can be shadowed by an instance attribute.

The Distinction

A data descriptor defines __set__ or __delete__ (or both) in addition to __get__. It takes priority over the instance's __dict__ in the lookup chain.

A non-data descriptor defines only __get__. It can be shadowed by an instance attribute with the same name.

123456789101112131415161718192021222324252627282930
# Data descriptor – cannot be shadowed by instance __dict__ class DataDescriptor: def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get("_value", "no value") def __set__(self, obj, value): obj.__dict__["_value"] = value # Non-data descriptor – can be shadowed class NonDataDescriptor: def __get__(self, obj, objtype=None): if obj is None: return self return "from descriptor" class Example: data = DataDescriptor() non_data = NonDataDescriptor() example = Example() # Trying to shadow the data descriptor example.__dict__["data"] = "shadowed attempt" print(example.data) # Still calls __get__ – data descriptor wins # Shadowing the non-data descriptor example.__dict__["non_data"] = "instance value" print(example.non_data) # "instance value" – instance __dict__ wins

Why the Distinction Matters

Data descriptors are used when you want to enforce behavior on every read and write – validation, type checking, computed properties. The instance cannot bypass the descriptor by setting an attribute directly.

Non-data descriptors are used for behavior that should be overridable per instance – functions are the primary example (covered in Chapter 4).

The Priority Table

A Practical Example

A data descriptor for validated string attributes that cannot be bypassed:

12345678910111213141516171819202122232425262728
# Data descriptor enforcing non-empty strings class NonEmptyString: def __set_name__(self, owner, name): self._name = name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name, "") def __set__(self, obj, value): if not isinstance(value, str) or not value.strip(): raise ValueError(f"{self._name} must be a non-empty string, got {value!r}") obj.__dict__[self._name] = value.strip() class Employee: name = NonEmptyString() department = NonEmptyString() def __init__(self, name, department): self.name = name self.department = department employee = Employee("Alice", "Engineering") print(employee.name) # "Alice" # Trying to bypass via __dict__ has no effect – __set__ is always called employee.name = "" # Raises ValueError

Read-Only Data Descriptors

A descriptor with __get__ and __delete__ but no __set__ is also a data descriptor – and attempting to set it raises AttributeError:

123456789101112131415161718192021222324
# Read-only data descriptor using __set__ to raise AttributeError class ReadOnly: def __set_name__(self, owner, name): self._name = "_" + name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name) def __set__(self, obj, value): if self._name in obj.__dict__: raise AttributeError(f"{self._name[1:]} is read-only") obj.__dict__[self._name] = value # Allowing the initial set from __init__ class Transaction: transaction_id = ReadOnly() def __init__(self, transaction_id): self.transaction_id = transaction_id # Initial set allowed transaction = Transaction("TX-001") print(transaction.transaction_id) # "TX-001" transaction.transaction_id = "TX-002" # Raises AttributeError
question mark

Why can a non-data descriptor be shadowed by an instance attribute but a data descriptor cannot?

Seleziona la risposta corretta

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 1. Capitolo 3

Chieda ad AI

expand

Chieda ad AI

ChatGPT

Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione

Sezione 1. Capitolo 3
some-alt