Python Tutorial
Python Variable
Python Operators
Python Sequence
Python String
Python Flow Control
Python Functions
Python Class and Object
Python Class Members (properties and methods)
Python Exception Handling
Python Modules
Python File Operations (I/O)
In Python, descriptors are a powerful feature that allows you to customize the behavior of how an object's attributes are accessed, modified, and deleted. Descriptors are classes that define one or more of the following special methods: __get__
, __set__
, and __delete__
.
In this tutorial, we will learn how to create a descriptor in Python and use it to control access to an attribute.
Example: Creating a Descriptor
Let's create a descriptor called PositiveNumber
that ensures that a number is always positive:
class PositiveNumber: def __init__(self, value): self.value = value def __get__(self, instance, owner): return self.value def __set__(self, instance, value): if value < 0: raise ValueError("Value cannot be negative") self.value = value def __delete__(self, instance): del self.value
In this example, we define the PositiveNumber
descriptor with the following methods:
__get__()
method is called when the descriptor is accessed. It takes the instance and the owner class as arguments and returns the value of the descriptor.__set__()
method is called when the descriptor is modified. It takes the instance and the new value as arguments. In this case, the method checks if the new value is negative and raises a ValueError
if it is. Otherwise, it sets the value of the descriptor.__delete__()
method is called when the descriptor is deleted. It takes the instance as an argument and deletes the value of the descriptor.Using the Descriptor in a Class
Now, let's use the PositiveNumber
descriptor in a class called Product
:
class Product: def __init__(self, name, price): self.name = name self.price = PositiveNumber(price)
In this example, we create a Product
class with a name
attribute and a price
attribute that uses the PositiveNumber
descriptor. The PositiveNumber
descriptor ensures that the price
attribute is always positive.
Example: Using the Descriptor
Let's create instances of the Product
class and see how the descriptor works:
# Create a Product instance product1 = Product("Laptop", 1000) # Access the price attribute print(product1.price) # Output: 1000 # Modify the price attribute product1.price = 1200 print(product1.price) # Output: 1200 # Try to set a negative price try: product1.price = -500 except ValueError as e: print(e) # Output: Value cannot be negative
In this example, we create a Product
instance and access, modify, and try to set a negative value for the price
attribute. The PositiveNumber
descriptor ensures that the price
attribute is always positive and raises a ValueError
if a negative value is attempted.
In conclusion, Python descriptors provide a way to control access to an object's attributes by customizing their behavior. Descriptors can be used to enforce data validation, implement computed properties, and more. By understanding and using descriptors, you can create more powerful and flexible classes in Python.
Creating custom descriptors in Python:
__get__
, __set__
, and __delete__
methods.class CustomDescriptor: def __get__(self, instance, owner): return instance._value def __set__(self, instance, value): if value < 0: raise ValueError("Value must be non-negative") instance._value = value class MyClass: descriptor = CustomDescriptor() def __init__(self, value): self._value = value
Built-in descriptor types in Python:
property
, classmethod
, and staticmethod
.class MyClass: @property def my_property(self): return self._value @my_property.setter def my_property(self, value): if value < 0: raise ValueError("Value must be non-negative") self._value = value
Getter and setter methods in descriptors:
class DescriptorWithGetterSetter: def __get__(self, instance, owner): return instance._value def __set__(self, instance, value): if value < 0: raise ValueError("Value must be non-negative") instance._value = value class MyClass: descriptor = DescriptorWithGetterSetter() def __init__(self, value): self._value = value
Decorators and descriptors in Python:
property
decorator is an example of a descriptor.class MyClass: @property def my_property(self): return self._value @my_property.setter def my_property(self, value): if value < 0: raise ValueError("Value must be non-negative") self._value = value