En Python, el decorador @property permite crear "atributos virtuales": métodos que se ven y se utilizan como campos normales, pero que ejecutan la lógica del getter, setter o deleter. Esto es conveniente para crear propiedades calculadas o controlar el acceso a los datos.
Ejemplo:
class Rectangle: def __init__(self, width, height): self._width = width self._height = height @property def area(self): return self._width * self._height @property def width(self): return self._width @width.setter def width(self, value): if value <= 0: raise ValueError('El ancho debe ser positivo') self._width = value r = Rectangle(3, 4) print(r.area) # 12 (se llama como propiedad, no como función) r.width = 10 # setter se llama automáticamente
¿Se puede usar solo un @property (método getter) sin definir un setter? ¿Qué sucederá si se intenta cambiar tal atributo?
Respuesta: Se puede definir solo el getter @property sin el setter (y deleter). Tal atributo será de solo lectura, y el intento de asignación generará un AttributeError.
class C: @property def x(self): return 42 c = C() c.x = 99 # AttributeError: can't set attribute
Historia
Se intentó serializar un objeto usando la biblioteca estándar, utilizando vars(obj) para obtener un diccionario de atributos. Resultó que los métodos de property no se incluyen en la salida de __dict__, sus valores no se serializaron, lo que llevó a una fuga de datos.
Historia
En un proyecto, se olvidó agregar un setter para property, y al intentar cambiar el valor de un campo calculado, se producía un error en tiempo de ejecución, aunque esto era lo que se esperaba según la lógica de arquitectura.
Historia
En el código en funcionamiento, el cálculo del valor de la propiedad permitía operaciones pesadas o inseguras, que se invocaban inesperadamente en cada acceso a la propiedad. Esto redujo el rendimiento y llevó a llamadas bloqueantes en código multihilo.