A simple, fast, typed, and tested abstract and base classes for a python3.6+ Non Data Descriptor, Data Descriptor, and Slottable Data Descriptor. The goal is to aid in the creation of descriptors allowing other developers to make descriptors for their own use case.
- Easy: Flexable and easy to inherit the prebuilt Non Data Descriptors, Data Descriptors, and Slottable Data Descriptors to create your own descriptors.
- Great Developer Experience: Being fully typed makes it great for editor support.
- Fully Tested: Our test suit fully tests the functionality to ensure that all of the classes in this module run as expected.
pip install base-descriptor
- Objects Provided in this Module
- Non Data Descriptor Examples
- Data Descriptor Examples
- Slottable Data Descriptors
- References
A non-data descriptor in Python is a type of descriptor that only implements
the __get__()
method. Descriptors are a way to customize attribute access in
Python. When an attribute is
accessed on an object, Python checks if a descriptor exists for that attribute
in the class or its ancestors. If found, the descriptor's __get__()
method is
called to determine the final
value of the attribute.
Class | Description |
---|---|
AbstractNonDataDescriptor |
Abstract Base Class for creating Non Data Descriptors. |
A data descriptor in Python is a type of descriptor that implements
both __get__()
and either __set__()
or __delete__()
. Data descriptors
allow you to define custom behavior for
attribute
access, including setting or deleting the attribute in addition to retrieving
its value.
Class | Description |
---|---|
AbstractDataDescriptor |
Abstract Base Class for creating Data Descriptors. |
BaseDataDescriptor |
Base Class for creating Data Descriptors. Provides the same functionality as a standard attribute. |
DefaultDescriptor |
A Data Descriptor that has a default value. |
ReadOnly |
A Data Descriptor that is read only. |
A Data Descriptor that plays well with __slots__
. This module was inspired by
Dr. Fred Baptiste fbaptiste.
The slottable data descriptor has the following advantages:
- Has instance specific storage
- Does not use the instance for storage, thus works with slots.
__slots__ = "__weakref__"
must be set. - Handles non hashable instances
- Data storage is clean.
Class | Description |
---|---|
AbstractSlottableDataDescriptor |
Abstract Base Class for creating Slottable Data Descriptors. |
BaseSlottableDataDescriptor |
Base Class for creating Slottable Data Descriptors. Provides the same functionality as a standard attribute. |
SlottableDefaultDescriptor |
A Slottable Data Descriptor that has a default value. |
Simple way to Inherit from AbstractNonDataDescriptor
to create your own Non
Data Descriptor.
from base_descriptor import AbstractNonDataDescriptor
class SquareDescriptor(AbstractNonDataDescriptor):
def __get__(self, instance, owner=None):
if instance is None:
# Access through the class, return the descriptor itself
return self
return instance._value ** 2
class MyClass:
square = SquareDescriptor()
def __init__(self, value):
self._value = value
# Create an instance of MyClass
my_instance = MyClass(5)
# Access the square attribute using the descriptor
# This will calculate and return the square
print(my_instance.square) # 25
from base_descriptor import ReadOnly
class Person:
name = ReadOnly("Guido")
person = Person()
print(person.name) # Guido
person.name = "Raymond" # raises AttributeError
Default Descriptor that provides a default value for the attribute.
from base_descriptor import DefaultDescriptor
class Person:
name = DefaultDescriptor(default="Guido")
print(Person.name) # <data_descriptor.DefaultDescriptor object at ...>
person = Person()
print(person.name) # Guido
person.name = "Raymond"
print(person.name) # Raymond
Provides the same functionality as a standard attribute.
It enables you to create your own Data Descriptor by overriding
the __set_name__()
, __set__()
, __get__()
,
or __delete__()
methods to match your requirements.
from base_descriptor import BaseDataDescriptor
class Plus2(BaseDataDescriptor):
def __set__(self, instance, value):
value = value + 2
instance.__dict__[self._property_name] = value
class Foo:
bar = Plus2()
foo = Foo()
foo.bar = 1
print(foo.bar) # 3
Provides an Abstract Base Class that can be inherited from to help create your own Data Descriptors.
from base_descriptor import AbstractDataDescriptor
class MyDataDescriptor(AbstractDataDescriptor):
def __init__(self):
self._value = None
def __get__(self, instance, owner):
return self._value
def __set__(self, instance, value):
self._value = value
def __delete__(self, instance):
self._value = None
class MyClass:
my_data_descriptor = MyDataDescriptor()
obj = MyClass()
obj.my_data_descriptor = 1
print(obj.my_data_descriptor) # 1
Slottable Default Descriptor that provides a default value for the attribute.
from base_descriptor import SlottableDefaultDescriptor
class Person:
__slots__ = "__weakref__"
first_name = SlottableDefaultDescriptor(default="Guido")
person = Person()
print(person.first_name) # Guido
person.first_name = "Raymond"
print(person.first_name) # Raymond
Provides the same functionality as a standard attribute.
It enables you to create your own Slottable Data Descriptor by overriding
the __set_name__()
, __set__()
, __get__()
,
or __delete__()
methods to match your requirements.
from base_descriptor import BaseSlottableDataDescriptor
class MyDescriptor(BaseSlottableDataDescriptor):
def __set__(self, instance, value):
print(f"Setting {self._property_name} to {value}")
instance.__dict__[self._property_name] = value
class Foo:
__slots__ = "__weakref__"
bar = MyDescriptor()
foo = Foo()
foo.bar = 1
print(foo.bar) # 1
This module was heavily inspired by the following resources:
-
Python Deep Dive: Part 4
- Author: Dr. Fred Baptiste (fbaptiste)
- Year: 2023
- Course Title: Python Deep Dive: Part 4
- Platform: Udemy
-
Descriptor HowTo Guide
- Source: Python Documentation
- URL: Descriptor HowTo Guide