Un descriptor es un objeto que implementa cualquiera de los métodos get, set y delete. Permite controlar el acceso a los atributos de una clase.
Métodos estándar de un descriptor:
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)Los descriptores pueden ser:
Ejemplo de uso:
class OnlyPositive: def __init__(self): self._name = '_value' def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if value < 0: raise ValueError('El valor debe ser >= 0') instance.__dict__[self._name] = value class Account: value = OnlyPositive() def __init__(self, value): self.value = value acc = Account(10) acc.value = -1 # ¡ValueError!
property es solo un azúcar sintáctico para crear descriptores a nivel de clase.
¿Qué pasará si se crea un descriptor como atributo de instancia, en lugar de clase?
Muchos creen que el descriptor funcionará, pero no es así.
Respuesta correcta:
El descriptor funciona solo si se define directamente como un atributo de clase. Si se establece un descriptor como atributo de instancia, los métodos get/set no se llamarán — lógica normal de acceso al atributo.
Historia
Uso de property en lugar de un descriptor completo
Para la validación y otros atributos relacionados, el desarrollador utilizó un simple property, lo que llevó a la frecuente duplicación de lógica y a la imposibilidad de reutilizar código entre diferentes clases.
Historia
No respetar la inmutabilidad al reutilizar almacenamiento
El descriptor almacenaba datos en un atributo interno de su propia clase (self.x), y no en el almacenamiento interno de la instancia, lo que hacía que el atributo se volviera "compartido", y diferentes instancias de la clase sobrescribían los valores entre sí — los datos "fugaban" entre los objetos.
Historia
Confundido data descriptor y non-data descriptor
En una jerarquía compleja se omitió la implementación de set, lo que provocó que el atributo normal de la instancia sobrescribiera el descriptor, rompiendo todo el mecanismo de validación — el error no se manifestaba siempre, complicado de depurar.