¿Cómo funcionan los decoradores en la programación orientada a objetos?
Los decoradores en Python son un elemento poderoso que añade funcionalidad adicional a métodos o funciones sin modificar su estructura interna. Este concepto es bien conocido en el contexto de funciones, pero su aplicación en la programación orientada a objetos (POO) expande aún más sus posibilidades. Aquí exploramos su uso dentro de clases.
¿Qué es un método estático?
Los métodos estáticos no dependen de la instancia de la clase sino que pertenecen a la clase en sí. Se utiliza el decorador @staticmethod cuando se desea crear un método que no necesita acceder a la clase o modificar sus datos.
classCalculadora:@staticmethoddefsuma(a:int, b:int)->int:return a + b
Ventaja: Ideal para operaciones que no requieren acceso a las propiedades o métodos de clase.
¿Qué hace un método de clase?
Un método de clase está vinculado a la clase y no a la instancia. Utiliza el decorador @classmethod, y el primer parámetro siempre es cls, que representa la clase.
classContador: cuenta =0@classmethoddefincrementar(cls): cls.cuenta +=1
Uso común: Modificar el estado de clase común a todas las instancias.
¿Cómo se utiliza el decorador property?
El decorador property permite acceder a un método como si fuese un atributo. Esto mejora la encapsulación y mantiene el control sobre cómo se manipula la información interna de la clase.
Ejemplo de clase Círculo
classCirculo:def__init__(self, radio:float): self._radio = radio
@propertydefarea(self)->float:return3.1416* self._radio **2@propertydefradio(self)->float:return self._radio
@radio.setterdefradio(self, valor:float):if valor <0:raise ValueError("El radio no puede ser negativo") self._radio = valor
¿Por qué usar property?
Control del acceso: El acceso a atributos sensibles puede ser controlado sin afectar la interfaz externa.
Flexibilidad: Los atributos pueden ser modificables, lo que permite agregar lógica para validaciones o cálculos al cambiar valores.
Encapsulación: Permite ocultar la lógica de cálculo o validaciones, entregando una interfaz limpia al usuario de la clase.
Reflexiones finales sobre decoradores en POO
Los decoradores como staticmethod, classmethod, y property son herramientas valiosas que enriquecen el diseño de clases en Python. Permiten:
Añadir funcionalidad especial sin modificar el código base.
Mejorar la legibilidad y profesionalidad del código.
Mantener un diseño orientado a objetos disciplinado y eficiente.
¡Ahora depende de ti aplicarlos y descubrir todo su potencial en tus proyectos! Recuerda: ¡Un gran poder conlleva una gran responsabilidad en el código!
Decoradores en Programación Orientada a Objetos en Python
En Python, los decoradores no solo se usan en funciones, también se pueden aplicar a clases y métodos para extender o modificar su comportamiento. Los decoradores en clases y métodos son especialmente útiles para aspectos transversales como la validación de permisos, el registro de accesos, el manejo de excepciones y la administración de cachés.
Aquí tienes una guía rápida sobre cómo funcionan y un ejemplo detallado:
### Decoradores en Métodos de Clase
Los decoradores pueden aplicarse a métodos específicos de una clase, y se comportan según el tipo de método:
- **Métodos de instancia** (los métodos normales que acceden a self).
- **Métodos de clase** (aquellos que usan @classmethod y acceden a cls).
- **Métodos estáticos** (usando @staticmethod, no acceden ni a self ni a cls).
Los decoradores en métodos de clase pueden hacer cosas como:
1. Controlar permisos antes de ejecutar el método.
2. Hacer un registro (logging) cada vez que se llama al método.
3. Manejar errores de forma consistente.
### Decoradores en Clases
Un decorador en una clase modifica el comportamiento de la clase en su conjunto, normalmente para extenderla o agregarle nuevas funcionalidades.
### Ejemplo de Uso
Imaginemos una clase CuentaBancaria donde queremos aplicar un decorador para registrar cada vez que se realiza una operación, y otro decorador para comprobar permisos de acceso a ciertas operaciones.
from functools import wraps
import datetime
\# Decorador para verificar permisos
def verificar\_permisos(permiso\_necesario):  def decorador\_metodo(func):  @wraps(func)  def envoltura(self, \*args, \*\*kwargs):  if permiso\_necesario not in self.permisos:  raise PermissionError(f"No tienes permisos para realizar esta operación: {permiso\_necesario}")  return func(self, \*args, \*\*kwargs)  return envoltura  return decorador\_metodo
\# Decorador para registrar en log
def registrar\_operacion(func):  @wraps(func)  def envoltura(self, \*args, \*\*kwargs):  resultado = func(self, \*args, \*\*kwargs)  operacion = f"{func.\_\_name\_\_} ejecutado el {datetime.datetime.now()}"  self.historial.append(operacion)  print(f"Registro: {operacion}")  return resultado  return envoltura
\# Clase CuentaBancaria usando decoradores en sus métodos
classCuentaBancaria:  def \_\_init\_\_(self, balance=0):  self.balance = balance  self.historial = \[]  self.permisos = \['ver\_balance', 'retirar'] # permisos actuales del usuario  @registrar\_operacion  @verificar\_permisos('ver\_balance')  def ver\_balance(self):  print(f"Balance actual: ${self.balance}")  return self.balance  @registrar\_operacion  @verificar\_permisos('retirar')  def retirar(self, cantidad):  if cantidad > self.balance:  raise ValueError("Fondos insuficientes")  self.balance -= cantidad  print(f"Retiro exitoso: ${cantidad}. Nuevo balance: ${self.balance}")  return self.balance
\# Uso de la clase con decoradores
cuenta = CuentaBancaria(1000)
\# Operaciones
cuenta.ver\_balance()cuenta.retirar(200)
\# Intento de retiro sin permisos
try:  cuenta.permisos.remove('retirar')  cuenta.retirar(100)except PermissionError as e:  print(e)
### Explicación
1. **@verificar\_permisos**: Este decorador toma un parámetro, permiso\_necesario, y se asegura de que el usuario tenga el permiso adecuado antes de ejecutar el método.
2. **@registrar\_operacion**: Este decorador registra cada operación realizada, almacenándola en el atributo historial.
Este patrón es muy poderoso para clases que requieren varias verificaciones y registros en sus métodos, proporcionando una estructura de código limpia y modular.
gracias por la aportacion
Gracias por tu aporte!
creo, que solo lanza ejemplos muy al aire, tan solo no probo el ejemplo de calculadora... solo dejo al aire la idea. Parece que no hay una estructura en los conceptos que explica.
Ha sido una constante en todo el curso. Diría que un 40-50% me lo ha explicado chatgpt.
sí, coincido contigo... tenía que haber explicado que la clase calculadora con @staticmethod sólo sirve ahí como clasificador o etiqueta de funciones como para no perderlas de vista en el código, podía haber añadido otros def de matemática para que quedara claro, esta es la explicación de chatgpt: Porque a veces organizar lógicamente funciones relacionadas dentro de una clase mejora la claridad, sobre todo en proyectos grandes. Es una forma de agrupar funciones coherentes.
En Python, property y setter son decoradores que permiten gestionar el acceso a los atributos de una clase de forma controlada.
property: Este decorador permite acceder a un método como si fuera un atributo. Por ejemplo, si tenemos un método que calcula el área de un círculo, al usar property, podemos acceder a este método sin paréntesis, como si fuera un atributo.
setter: Se usa para definir un método que permite modificar el valor de un atributo de forma segura. Por ejemplo, puedes validar que el nuevo valor no sea negativo antes de asignarlo a un atributo.
Estos decoradores ayudan a encapsular la lógica de la clase y proporcionan un control más estricto sobre cómo se accede y modifica la información.
Gracias por tu aporte!
No termino de entender para qué usar decoradores, por ejemplo, en el ejemplo del área del círculo, por que no sencillamente no se crea un atributo como self.area = (radius**2)*3.1416 y ya, los atributos extienden la funcionalidad sin embargo no veo la razón de usarlos si simplemente se pueden dar esas características y funciones a la clase y ya.
@property Facilita el acceso y la modificación de atributos de manera controlada, permitiendo la validación y el encapsulamiento.
A mi modo de ver, este decorador tiene dos ventajas: 1. Poder convertir el resultado de un método en un atributo y 2. Poder tener este atributo de manera interna y más privada.
alguien tiene informacion de los decoradores?
no he entendido nada, como funcionan?
Un decorador es una función que se ejecuta antes de la función al que se la asignas.
#Ejemplo
def tieneDinero():
@tieneDinero
def comprar():
Antes de ejecutar comprar el decorador con la función tieneDinero se ejecuta antes y ahi puedes escribir la lógica que desees, el uso más común es de validar y formatear datos, pero lo puedes usar para lo que sea.
Creo que no es algo que si no se entiende o se usa a la primera esté mal. Por ahora, veo estos decoradores como formas en el que el código está "mejor" escrito. Algo más "profesional", mejor visto para los profesionales
No, no se puede utilizar el decorador @nombre_del_metodo.setter sin haber definido previamente el decorador @property para ese mismo método. El decorador @property convierte el método en un atributo, lo que permite el uso del decorador @setter para modificar su valor. Esto es fundamental en Python para garantizar que se mantenga la consistencia y el control sobre la asignación de valores a los atributos de la clase.
Alguien me podría comentar la diferencia entre llamar al atributo self.radius y self._radius?
No entiendo muy bien por qué se coloca el guion previo al nombre del atributo.
Muy buen punto y observación.
Respuesta:
En Python, es común usar un prefijo como _ en los atributos de instancia para diferenciarlos de los parámetros del constructor. En el ejemplo, radius es el parámetro del método __init__, mientras que self._radius es el atributo que guarda el valor. Esto evita confusiones y permite reconocer fácilmente que _radius es un atributo de la instancia. Esta convención facilita el acceso y la modificación del atributo dentro de la clase sin conflictos con los parámetros pasados al constructor.
Espero haber sido claro, sino con mucho gusto trato de explicarlo mejor. Saludos.
Decoradores predefinidos como el @staticmethod : existe incluso antes de cualquier instancia de la clase, @classmethod: hacen modificacion del estado de la clase
,@propperti : permite que los metodos se comporten como atributos aplicando encapsulamiento
son especialmente
decoradores de biblioteca como: @functools.wraps @lru_cache @contextManager, @dataclass
proporcionan funcionalidades adicionales y optimizaciones
decoradores personalizados pueden usarse para registro validaciones o timers
Decoradores que incluye python: Decoradores para Métodos en Clases
@staticmethodpythonCopiar códigoclass MiClase:
@staticmethod def metodo_estatico():
print("Este es un método estático.")
MiClase.metodo_estatico()
Convierte un método en un método estático.
El método estático no recibe ni self ni cls como argumento.
Se utiliza para definir funciones relacionadas con la clase, pero que no dependen de una instancia.
Ejemplo:
@classmethodpythonCopiar códigoclass MiClase:
@classmethod def metodo_clase(cls):
print("Este es un método de clase.")
MiClase.metodo_clase()
Convierte un método en un método de clase.
Recibe cls como primer argumento, que representa la clase (no la instancia).
Se utiliza cuando se necesita acceder a atributos o métodos de clase.
Ejemplo:
@propertypythonCopiar códigoclass MiClase:
def __init__(self, valor):
self._valor = valor
@property def valor(self):
return self._valor
obj = MiClase(10)
print(obj.valor) # Accede al atributo con lógica adicional.
Convierte un método en un getter para un atributo.
Se utiliza para acceder a atributos como si fueran propiedades, lo que permite definir lógica adicional al obtener un valor.
Ejemplo:
@<property>.setterpythonCopiar códigoclass MiClase:
def __init__(self, valor):
self._valor = valor
@property def valor(self):
return self._valor
@valor.setter def valor(self, nuevo_valor):
self._valor = nuevo_valor
obj = MiClase(10)
obj.valor = 20 # Cambia el valor con lógica adicional.print(obj.valor)
Permite definir un setter para un atributo, utilizado para establecer valores con lógica adicional.
Ejemplo:
@<property>.deleterpythonCopiar códigoclass MiClase:
def __init__(self, valor):
self._valor = valor
@property def valor(self):
return self._valor
@valor.deleter def valor(self):
del self._valor
obj = MiClase(10)
del obj.valor # Lógica al eliminar.
Permite definir un deleter para un atributo, utilizado para eliminar valores con lógica adicional.
Ejemplo:
Decoradores para Corrutinas y Generadores
@asyncio.coroutine(obsoleto en Python 3.10)
Usado para definir funciones generadoras asíncronas en versiones anteriores de Python.
Especifica diferentes firmas de funciones para sobrecarga de funciones (solo para propósitos de tipado).
Los modificadores utilizados en el contexto de decoradores en Programación Orientada a Objetos en Python son:
@staticmethod: Se utiliza para definir un método que no accede a la instancia o clase.
@classmethod: Permite modificar la clase o acceder a atributos de clase, en vez de a la instancia.
@property: Facilita acceder a un método como si fuera un atributo, permitiendo también la creación de setters.
Estos decoradores ayudan a estructurar el código y a mantener buenas prácticas en programación orientada a objetos.
Esto lo redactaste con AI bro jajajaja
Todo en esta clase esta mal explicado. Lo que entendí:
@staticmethod te brinda la posibilidad de crear un método estático, es decir, que no necesitas crear una instancia de la clase para usar el método. Util para tener métodos agrupados para unac misma funcionalidad, pero que no necesiten acceder a información interna de la clase.
El @classmethod se usa cuando necesitas que el método tenga acceso a la clase (usando cls) en lugar de a un objeto específico (self). Es ideal para gestionar un estado compartido por todas las instancias (atributos de clase)
@property permite convertir un método en un "atributo virtual" o "computado". Es decir, puedes acceder a un método como si fuera una variable normal, sin usar paréntesis ()
@radius.setter se utiliza para definir el comportamiento de la aplicación de un nuevo valor al atributo "virtual" en este caso radius. Para usarlo se tiene que haber definido antes un atributo virtual con @property
Hola! Siento que el contenido es bastante completo sin embargo veo que muchas clases son mas un ejemplo en el que se aplican conceptos que no se están dando, sé que gran parte es autoaprendizaje pero es muy difícil si inicialmente no se da una sintaxis, un por qué se usa y al final si el ejemplo, solo siento que es un repaso y en mi caso solo entiendo esos ejemplos cuando son temas que yo domino, más que queja lo comento para cursos futuros ya que lo ideal no es entrar aquí para salir a buscar toda la teoría en otras fuentes.
Estoy de acuerdo, esta clase en especifico estuvo muy mal explicada, en lugar de explicar cada uno de los decoradores y luego poner un ejemplo de caso de uso real donde implemente los mismos, solo se limito a escribir el codigo y no explico nada. Si solo quisiera ver ejemplo, se lo podria preguntar a ChatGPT. Además, en mi caso tengo experiencia en otros lenguajes, pero hay muchos que básicamente están aprendiendo a programar con este curso.
Debes usar el decorador @staticmethod en Python. Este decorador se aplica a un método que no requiere acceso a la instancia (self) ni a la clase (cls). Los métodos estáticos son útiles para agrupar funciones relacionadas con la clase, pero que no necesitan acceder a sus atributos ni modificar su estado.
Esto ya se podría considerar como avanzado?
La clase prepara para escribir código Pythonico y profesional, es momento de dar un paso más y enfrentar desafíos más complejos.
```js
def decorador_clase(cls):
cls.autor = "Ingeniero de Datos"
return cls
@decorador_clase
class Informe:
pass
print(Informe.autor)
Me parece algo complejo de entender, pero lo poco que comprendí es que los decoradores funcionan como una función que se realiza antes de realizar la función original.
Lo tomo como si en el ordenador cuando nosotros queremos eliminar algún archivo nos salta una ventana de alerta para preguntarnos si estamos seguros.
En este caso la función original seria la de eliminar el archivo y el decorador como la ventana emergente de alerta.
Me podrían confirmar si estoy en lo cierto o me estoy equivocando por favor.
¿Qué decorador se utiliza para métodos que no acceden a la información de la clase?
A) @classmethod
B) @staticmethod (Correcta)
C) @property
D) @decorador
¿Cuál de los siguientes decoradores permite modificar atributos de la clase?
A) @staticmethod
B) @classmethod (Correcta)
C) @property
D) @decorador
¿Qué decorador se utiliza para acceder a métodos como si fueran atributos?
A) @staticmethod
B) @classmethod
C) @property (Correcta)
D) @decorador
En el contexto de la clase Calculadora, ¿qué tipo de datos recibe el método sumar?
A) Flotantes
B) Cadenas
C) Enteros (Correcta)
D) Listas
¿Qué error se levanta cuando se intenta asignar un valor negativo al radio en la clase Círculo?
A) ValueError (Correcta)
B) TypeError
C) AttributeError
D) IndexError
¿Qué método se utiliza para incrementar un contador en la clase Contador?
A) increment
B) add
C) count (Correcta)
D) sum
¿Cómo se define el decorador para un método de clase?
A) @staticmethod
B) @classmethod (Correcta)
C) @property
D) @decorador
¿Qué valor retorna el método área en la clase Círculo?
A) El radio
B) 3.14 * radio^2 (Correcta)
C) Un número entero
D) Un string
¿Qué función cumple el decorador @property en un método setter?
A) Modifica un atributo (Correcta)
B) Solo devuelve un valor
C) Define un método estático
D) No tiene función
¿Qué se puede concluir sobre el uso de decoradores en Python?
A) Son opcionales
B) Ayudan a extender funcionalidades (Correcta)
C) Son obsoletos
D) Solo se usan con funciones
quede muy perdido en esta clase!!!
creo que la metodologia de esta clase o la de toda la seccion de decoradores puede mejorarse porque hay muchos vacios y deja mucho hueco solo lo explica superficialmente y creo que es tema algo complejo
Si es bastante complejo, y creo que si lo explicara más a fondo la clse se alargaria mucho o incluso podria tomar varias clases, por eso me parece que solo te sueltan el tema para que lo conoscas y luego tu lo profundices por tu cuenta
Analogía para los que sepan algo de SQL y quieran entender como funciona @radius.setter ⇒
Un @<nombre_propiedad>.setter se comporta de manera muy similar a un trigger en una base de datos. Un trigger es un bloque de código que se ejecuta automáticamente en respuesta a ciertos eventos (como la inserción, actualización o eliminación de datos).
De la misma manera, el método decorado con @<nombre_propiedad>.setter se "dispara" o se ejecuta automáticamente cuando se intenta asignar un valor al atributo correspondiente de un objeto de la clase.
Y al igual que los triggers en bases de datos pueden realizar diversas acciones (verificar la integridad de los datos, actualizar otras tablas, registrar eventos, etc.), el setter en Python puede contener cualquier lógica que necesites ejecutar en el momento en que se modifica el valor del atributo:
Verificar: Como en el ejemplo del radio positivo.
Transformar: Como capitalizar un nombre o eliminar espacios.
Actualizar otros atributos: Como recalcular el área de un rectángulo.
Registrar (logging): Dejar constancia de la modificación.
Emitir eventos: Notificar a otras partes del sistema sobre el cambio.
Incluso "eliminar" (aunque esto sería menos común y más conceptual, podrías, por ejemplo, establecer una bandera interna o realizar otra acción en respuesta a un valor específico).
En resumen:
El @<nombre_propiedad>.setter actúa como un mecanismo de interceptación o un trigger que se activa cuando se intenta cambiar el valor de un atributo específico, permitiéndote ejecutar código personalizado en ese momento.
¿Qué hace@property?
@property es un decorador incorporado en Python que se utiliza para definir un método de clase que se accede como si fuera un atributo. Proporciona una forma elegante de implementar el acceso controlado a los atributos de una instancia, permitiendo ejecutar código (como cálculos o validaciones) cuando se intenta obtener el valor de un "atributo".
¿Para qué sirve@property?
Encapsulación y Control de Acceso: Permite ocultar la implementación interna de un atributo (como _radius) y proporcionar una interfaz controlada para obtener su valor (radius). Facilita la modificación interna sin romper el código que la utiliza.
Cálculo Dinámico de Atributos: Define "atributos" cuyo valor se calcula dinámicamente cada vez que se accede a ellos (como area).
Validación al Obtener: Permite incluir lógica de validación o transformación antes de devolver el valor (no usado en este ejemplo).
Transición Fluida de Atributo a Método: Permite convertir un atributo simple en un método (con cálculo) sin cambiar la forma de acceso en el resto del código (objeto.atributo).
classCircle: # Creamos un circulo que va a tener su respectiva radio
def __init__(self,radius: float): self._radius= radius
@property
def area(self)-> float:return3.1416*(self._radius**2)
@property
def radius(self)-> float:return self._radius# Creamos un circulo para probar
circle =Circle(5)print(circle.area)```**En tu código:**
* `__init__(self,radius: float)`: Inicializa el círculo con el radio en `_radius`.
* `@property def area(self)-> float:`: Define el método `area` accesible como `circle.area`, calculando el área dinámicamente.
* `@property def radius(self)-> float:`: Define el método `radius` accesible como `circle.radius`, devolviendo el valor de `_radius`.
**Salida de** `print(circle.area)`**:**
78.53981633974483
**En resumen:**
Has utilizado `@property` para crear un "atributo calculado" (`area`) y un acceso controlado a un atributo (`radius`), mejorando la encapsulación y flexibilidad de la clase `Circle`.