Can you explain the concept of Python descriptors and provide examples of how they can be used to customize attribute access?
Descriptors allow customizing attribute access. Here's a simple example:
class Celsius:
def __get__(self, instance, owner):
return instance._celsius
def __set__(self, instance, value):
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible.")
instance._celsius = value
class Temperature:
celsius = Celsius()
# Usage
temp = Temperature()
temp.celsius = 25
print(temp.celsius)