Skip to main content

A simple, fast, typed, and tested abstract and base classes for a python3.6+ Non Data Descriptor, Data Descriptor, and Slottable Data Descriptor.

Project description

Maintenance License: MIT codecov

base-descriptor

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.

Key Features:

  • 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.

Installation

pip install base-descriptor

Table of Contents

Objects Provided in this Module

Non Data Descriptors

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.

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.

Slottable Data Descriptors

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:

  1. Has instance specific storage
  2. Does not use the instance for storage, thus works with slots. __slots__ = "__weakref__" must be set.
  3. Handles non hashable instances
  4. 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.

Non Data Descriptor Examples

AbstractNonDataDescriptor

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

Data Descriptor Examples

ReadOnly

from base_descriptor import ReadOnly


class Person:
    name = ReadOnly("Guido")


person = Person()
print(person.name)  # Guido
person.name = "Raymond"  # raises AttributeError

DefaultDescriptor

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

BaseDataDescriptor

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

AbstractDataDescriptor

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 Data Descriptors

SlottableDefaultDescriptor

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

BaseSlottableDataDescriptor

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

References

This module was heavily inspired by the following resources:

  1. Python Deep Dive: Part 4

  2. Descriptor HowTo Guide

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

base-descriptor-1.2.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

base_descriptor-1.2-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file base-descriptor-1.2.tar.gz.

File metadata

  • Download URL: base-descriptor-1.2.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.18

File hashes

Hashes for base-descriptor-1.2.tar.gz
Algorithm Hash digest
SHA256 af114a7999091b6f8f7d9f125855db40069ec420200a05e68cd56911f769f65b
MD5 d557b6d6d6ba39101300c11656e2615a
BLAKE2b-256 5a10460ac28f1e582b8a76f1c30b845ac98858da2c6b21599e35a50fdb2011b3

See more details on using hashes here.

File details

Details for the file base_descriptor-1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for base_descriptor-1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 bb0b8de06ca0a77325c02126e39844b4a9187ed94ecca426257a467947c72c29
MD5 05325c068a00cb4090411cb75f330261
BLAKE2b-256 2ace7208b67d58c0a909c98bc94d4f4bbd52c42ae6eaad2350879c43a7c8495d

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page