Decoradores property en Python para atributos con validación
Clase 14 de 17 • Curso de Python Orientado a Objetos
Resumen
Los decoradores @property en Python convierten métodos en atributos accesibles con la anotación de punto, logrando interfaces limpias, validación y cálculo automático detrás de escena. Con un getter convertido en propiedad y un setter controlado, tu clase gana encapsulación efectiva sin cambiar cómo lees o escribes valores.
¿Qué es property y por qué hace tu código más pythonico?
Usar property permite exponer datos como atributos, pero con la lógica de métodos. Así, el acceso es natural y no requiere paréntesis, mientras mantienes el control interno.
- Convierte un método en atributo de solo lectura con @property.
- Controla la escritura con @nombre.setter y valida entradas.
- Accede con la anotación de punto, sin paréntesis.
¿Cómo convertir un getter en propiedad con @property?
Primero, elimina el método get_... y declara la propiedad. Luego úsala como un atributo.
class Libro:
def __init__(self, titulo, autor, ISBN):
self.titulo = titulo
self.autor = autor
self.ISBN = ISBN
self._veces_prestado = 0 # parámetro interno
@property
def veces_prestado(self):
return self._veces_prestado
En el flujo de impresión, en lugar de retornar solo el título desde libros_disponibles, retorna el objeto libro y accede así:
# en main
for libro in libros_disponibles():
print(libro.titulo, libro.veces_prestado) # sin paréntesis
¿Cómo controlar la escritura con setter y validación?
Con el setter defines cómo se asigna y validas valores. Si no cumple, genera un error claro.
class Libro:
# ...
@veces_prestado.setter
def veces_prestado(self, valor):
if valor > 0:
self._veces_prestado = valor
else:
raise ValueError("El valor de veces prestado debe ser mayor a cero")
Prueba en main asignando un valor negativo y ejecuta:
python main.py
Verás un ValueError con el mensaje de validación. Esto ayuda a detectar un bug antes de que llegue a usuarios reales.
¿Cómo usar properties para computar y mostrar datos?
Además de exponer valores, puedes crear propiedades que computan resultados a partir del estado interno. Por ejemplo, una propiedad es_popular basada en datos internos se accede como atributo y no necesita setter.
- Propiedades computadas como es_popular evitan estados inconsistentes.
- No declaras setter si no quieres permitir escritura.
Para mostrar información compuesta, crea una propiedad que devuelva una cadena con título, autor e ISBN.
class Libro:
# ...
@property
def descripcion_completa(self):
return f"{self.titulo} por {self.autor} {self.ISBN}"
Úsala en la salida en main con la anotación de punto:
print(libro.descripcion_completa)
¿Cómo se integra en main y biblioteca?
La integración es directa si retornas objetos libro en lugar de cadenas.
- Modifica libros_disponibles para retornar la lista de objetos Libro.
- Itera y accede a libro.titulo, libro.veces_prestado y libro.descripcion_completa.
- Evita paréntesis: las propiedades se leen como atributos.
- Ejecuta con python main.py para validar resultados.
¿Qué reto práctico puedes implementar ahora?
Pon en práctica las propiedades para reforzar encapsulación y claridad.
- Agrega una propiedad nombre completo a la clase usuario que combine nombre y cédula.
- Crea una propiedad en biblioteca para libros disponibles que retorne la lista de todos los libros disponibles.
- Comparte tu implementación y comenta cómo validaste las asignaciones.
¿Tienes otra idea de propiedad útil en tu modelo de dominio? Cuéntala en los comentarios y qué validaciones agregarías.