Aprende sobre decoradores de clase

PythonPythonBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, aprenderás sobre los decoradores de clase en Python y revisitarás y extenderás los descriptores de Python. Al combinar estos conceptos, puedes crear estructuras de código potentes y limpias.

En este laboratorio, construirás sobre conceptos de descriptores anteriores y los extenderás utilizando decoradores de clase. Esta combinación te permite crear un código más limpio y mantenible con capacidades de validación mejoradas. Los archivos que se deben modificar son validate.py y structure.py.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/BasicConceptsGroup(["Basic Concepts"]) python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/BasicConceptsGroup -.-> python/type_conversion("Type Conversion") python/ControlFlowGroup -.-> python/conditional_statements("Conditional Statements") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ObjectOrientedProgrammingGroup -.-> python/inheritance("Inheritance") python/ObjectOrientedProgrammingGroup -.-> python/encapsulation("Encapsulation") python/ObjectOrientedProgrammingGroup -.-> python/class_static_methods("Class Methods and Static Methods") python/AdvancedTopicsGroup -.-> python/decorators("Decorators") subgraph Lab Skills python/type_conversion -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/conditional_statements -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/function_definition -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/classes_objects -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/inheritance -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/encapsulation -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/class_static_methods -.-> lab-132516{{"Aprende sobre decoradores de clase"}} python/decorators -.-> lab-132516{{"Aprende sobre decoradores de clase"}} end

Implementación de la verificación de tipos con descriptores

En este paso, vamos a crear una clase Stock que utiliza descriptores para la verificación de tipos. Pero primero, entendamos qué son los descriptores. Los descriptores son una característica realmente poderosa en Python. Te dan control sobre cómo se accede a los atributos en las clases.

Los descriptores son objetos que definen cómo se accede a los atributos en otros objetos. Lo hacen implementando métodos especiales como __get__, __set__ y __delete__. Estos métodos permiten a los descriptores gestionar cómo se recuperan, establecen y eliminan los atributos. Los descriptores son muy útiles para implementar validación, verificación de tipos y propiedades calculadas. Por ejemplo, puedes usar un descriptor para asegurarte de que un atributo siempre sea un número positivo o una cadena de un cierto formato.

El archivo validate.py ya tiene clases validadoras (String, PositiveInteger, PositiveFloat). Podemos usar estas clases para validar los atributos de nuestra clase Stock.

Ahora, creemos nuestra clase Stock con descriptores.

  1. Primero, abre el archivo stock.py en el editor. Puedes hacer esto ejecutando el siguiente comando en tu terminal:
code ~/project/stock.py

Este comando utiliza el editor code para abrir el archivo stock.py ubicado en el directorio ~/project.

  1. Una vez abierto el archivo, reemplaza el contenido de marcador de posición con el siguiente código:
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    _fields = ('name', 'shares', 'price')
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

    @property
    def cost(self):
        return self.shares * self.price

    def sell(self, nshares):
        self.shares -= nshares

## Create an __init__ method based on _fields
Stock.create_init()

Analicemos lo que hace este código. La tupla _fields define los atributos de la clase Stock. Estos son los nombres de los atributos que tendrán nuestros objetos Stock.

Los atributos name, shares y price se definen como objetos descriptor. El descriptor String() asegura que el atributo name sea una cadena. El descriptor PositiveInteger() se asegura de que el atributo shares sea un entero positivo. Y el descriptor PositiveFloat() garantiza que el atributo price sea un número de punto flotante positivo.

La propiedad cost es una propiedad calculada. Calcula el costo total de la acción en función del número de acciones y el precio por acción.

El método sell se utiliza para reducir el número de acciones. Cuando llamas a este método con un número de acciones para vender, resta ese número del atributo shares.

La línea Stock.create_init() crea dinámicamente un método __init__ para nuestra clase. Este método nos permite crear objetos Stock pasando los valores de los atributos name, shares y price.

  1. Después de agregar el código, guarda el archivo. Esto asegurará que tus cambios se guarden y se puedan usar cuando ejecutes las pruebas.

  2. Ahora, ejecutemos las pruebas para verificar tu implementación. Primero, cambia el directorio al directorio ~/project ejecutando el siguiente comando:

cd ~/project

Luego, ejecuta las pruebas utilizando el siguiente comando:

python3 teststock.py

Si tu implementación es correcta, deberías ver una salida similar a esta:

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Esta salida significa que todas las pruebas están pasando. ¡Los descriptores están validando correctamente los tipos de cada atributo!

Intentemos crear un objeto Stock en el intérprete de Python. Primero, asegúrate de estar en el directorio ~/project. Luego, ejecuta el siguiente comando:

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Deberías ver la siguiente salida:

Stock('GOOG', 100, 490.1)
Cost: 49010.0

¡Has implementado con éxito descriptores para la verificación de tipos! Ahora, mejoremos este código aún más.

✨ Revisar Solución y Practicar

Creación de un decorador de clase para validación

En el paso anterior, nuestra implementación funcionó, pero había una redundancia. Teníamos que especificar tanto la tupla _fields como los atributos descriptor. Esto no es muy eficiente y podemos mejorarlo. En Python, los decoradores de clase son una herramienta poderosa que puede ayudarnos a simplificar este proceso. Un decorador de clase es una función que toma una clase como argumento, la modifica de alguna manera y luego devuelve la clase modificada. Al usar un decorador de clase, podemos extraer automáticamente la información de los campos de los descriptores, lo que hará nuestro código más limpio y mantenible.

Vamos a crear un decorador de clase para simplificar nuestro código. Estos son los pasos que debes seguir:

  1. Primero, abre el archivo structure.py. Puedes usar el siguiente comando en la terminal:
code ~/project/structure.py

Este comando abrirá el archivo structure.py en tu editor de código.

  1. A continuación, agrega el siguiente código en la parte superior del archivo structure.py, justo después de cualquier declaración de importación. Este código define nuestro decorador de clase:
from validate import Validator

def validate_attributes(cls):
    """
    Class decorator that extracts Validator instances
    and builds the _fields list automatically
    """
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Create initialization method
    cls.create_init()

    return cls

Analicemos lo que hace este decorador:

  • Primero crea una lista vacía llamada validators. Luego, itera sobre todos los atributos de la clase usando vars(cls).items(). Si un atributo es una instancia de la clase Validator, agrega ese atributo a la lista validators.
  • Después de eso, establece el atributo _fields de la clase. Crea una lista de nombres a partir de los validadores en la lista validators y la asigna a cls._fields.
  • Finalmente, llama al método create_init() de la clase para generar el método __init__ y luego devuelve la clase modificada.
  1. Una vez que hayas agregado el código, guarda el archivo structure.py. Guardar el archivo asegura que tus cambios se conserven.

  2. Ahora, necesitamos modificar nuestro archivo stock.py para usar este nuevo decorador. Abre el archivo stock.py usando el siguiente comando:

code ~/project/stock.py
  1. Actualiza el archivo stock.py para usar el decorador validate_attributes. Reemplaza el código existente con lo siguiente:
## stock.py

from structure import Structure, validate_attributes
from validate import String, PositiveInteger, PositiveFloat

@validate_attributes
class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

    @property
    def cost(self):
        return self.shares * self.price

    def sell(self, nshares):
        self.shares -= nshares

Observa los cambios que hemos hecho:

  • Agregamos el decorador @validate_attributes justo encima de la definición de la clase Stock. Esto le dice a Python que aplique el decorador validate_attributes a la clase Stock.
  • Eliminamos la declaración explícita de _fields porque el decorador se encargará de ello automáticamente.
  • También eliminamos la llamada a Stock.create_init() porque el decorador se encarga de crear el método __init__.

Como resultado, la clase ahora es más simple y limpia. El decorador se encarga de todos los detalles que solíamos manejar manualmente.

  1. Después de hacer estos cambios, necesitamos verificar que todo siga funcionando como se espera. Vuelve a ejecutar las pruebas usando los siguientes comandos:
cd ~/project
python3 teststock.py

Si todo está funcionando correctamente, deberías ver la siguiente salida:

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Esta salida indica que todas las pruebas se han pasado con éxito.

También probemos nuestra clase Stock de forma interactiva. Ejecuta el siguiente comando en la terminal:

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Deberías ver la siguiente salida:

Stock('GOOG', 100, 490.1)
Cost: 49010.0

¡Genial! Has implementado con éxito un decorador de clase que simplifica nuestro código manejando automáticamente las declaraciones de campos e inicialización. Esto hace que nuestro código sea más eficiente y fácil de mantener.

✨ Revisar Solución y Practicar

Aplicación de decoradores a través de la herencia

En el Paso 2, creamos un decorador de clase que simplifica nuestro código. Un decorador de clase es un tipo especial de función que toma una clase como argumento y devuelve una clase modificada. Es una herramienta útil en Python para agregar funcionalidad a las clases sin modificar su código original. Sin embargo, todavía necesitamos aplicar explícitamente el decorador @validate_attributes a cada clase. Esto significa que cada vez que creamos una nueva clase que necesita validación, tenemos que recordar agregar este decorador, lo cual puede ser un poco tedioso.

Podemos mejorar esto aún más aplicando el decorador automáticamente a través de la herencia. La herencia es un concepto fundamental en la programación orientada a objetos donde una subclase puede heredar atributos y métodos de una clase padre. El método __init_subclass__ de Python se introdujo en Python 3.6 para permitir que las clases padre personalicen la inicialización de las subclases. Esto significa que cuando se crea una subclase, la clase padre puede realizar algunas acciones sobre ella. Podemos usar esta característica para aplicar automáticamente nuestro decorador a cualquier clase que herede de Structure.

Vamos a implementar esto:

  1. Abre el archivo structure.py:
code ~/project/structure.py

Aquí, estamos usando el comando code para abrir el archivo structure.py en un editor de código. Este archivo contiene la definición de la clase Structure, y vamos a modificarla para usar el método __init_subclass__.

  1. Agrega el método __init_subclass__ a la clase Structure:
class Structure:
    _fields = ()
    _types = ()

    def __init__(self, *args):
        if len(args) != len(self._fields):
            raise TypeError(f'Expected {len(self._fields)} arguments')
        for name, val in zip(self._fields, args):
            setattr(self, name, val)

    def __repr__(self):
        values = ', '.join(repr(getattr(self, name)) for name in self._fields)
        return f'{type(self).__name__}({values})'

    @classmethod
    def create_init(cls):
        '''
        Create an __init__ method from _fields
        '''
        body = 'def __init__(self, %s):\n' % ', '.join(cls._fields)
        for name in cls._fields:
            body += f'    self.{name} = {name}\n'

        ## Execute the function creation code
        namespace = {}
        exec(body, namespace)
        setattr(cls, '__init__', namespace['__init__'])

    @classmethod
    def __init_subclass__(cls):
        validate_attributes(cls)

El método __init_subclass__ es un método de clase, lo que significa que se puede llamar en la propia clase en lugar de en una instancia de la clase. Cuando se crea una subclase de Structure, este método se llamará automáticamente. Dentro de este método, llamamos al decorador validate_attributes en la subclase cls. De esta manera, cada subclase de Structure tendrá automáticamente el comportamiento de validación.

  1. Guarda el archivo.

Después de hacer cambios en el archivo structure.py, necesitamos guardarlo para que los cambios se apliquen.

  1. Ahora, actualicemos nuestro archivo stock.py para aprovechar esta nueva característica:
code ~/project/stock.py

Estamos abriendo el archivo stock.py para modificarlo. Este archivo contiene la definición de la clase Stock, y vamos a hacer que herede de la clase Structure para usar la aplicación automática del decorador.

  1. Modifica el archivo stock.py para eliminar el decorador explícito:
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

    @property
    def cost(self):
        return self.shares * self.price

    def sell(self, nshares):
        self.shares -= nshares

Ten en cuenta que:

  • Eliminamos la importación de validate_attributes porque ya no necesitamos importarla explícitamente ya que el decorador se aplica automáticamente a través de la herencia.
  • Eliminamos el decorador @validate_attributes porque el método __init_subclass__ en la clase Structure se encargará de aplicarlo.
  • El código ahora se basa únicamente en la herencia de Structure para obtener el comportamiento de validación.
  1. Vuelve a ejecutar las pruebas para verificar que todo sigue funcionando:
cd ~/project
python3 teststock.py

Ejecutar las pruebas es importante para asegurarnos de que nuestros cambios no han roto nada. Si todas las pruebas pasan, significa que la aplicación automática del decorador a través de la herencia está funcionando correctamente.

Deberías ver que todas las pruebas pasan:

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Probemos de nuevo nuestra clase Stock para asegurarnos de que funciona como se espera:

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Este comando crea una instancia de la clase Stock e imprime su representación y el costo. Si la salida es como se espera, significa que la clase Stock está funcionando correctamente con la aplicación automática del decorador.

Salida:

Stock('GOOG', 100, 490.1)
Cost: 49010.0

¡Esta implementación es aún más limpia! Al usar __init_subclass__, hemos eliminado la necesidad de aplicar explícitamente decoradores. Cualquier clase que herede de Structure obtiene automáticamente el comportamiento de validación.

✨ Revisar Solución y Practicar

Adición de funcionalidad de conversión de filas

En programación, a menudo es útil crear instancias de una clase a partir de filas de datos, especialmente cuando se trabaja con datos de fuentes como archivos CSV. En esta sección, agregaremos la capacidad de crear instancias de la clase Structure a partir de filas de datos. Lo haremos implementando un método de clase from_row en la clase Structure.

  1. Primero, debes abrir el archivo structure.py. Aquí es donde realizaremos los cambios en el código. Utiliza el siguiente comando en tu terminal:
code ~/project/structure.py
  1. A continuación, modificaremos la función validate_attributes. Esta función es un decorador de clase que extrae instancias de Validator y construye automáticamente las listas _fields y _types. La actualizaremos para que también recopile información de tipos.
def validate_attributes(cls):
    """
    Class decorator that extracts Validator instances
    and builds the _fields and _types lists automatically
    """
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Set _types based on validator expected_types
    cls._types = [getattr(val, 'expected_type', lambda x: x) for val in validators]

    ## Create initialization method
    cls.create_init()

    return cls

En esta función actualizada, estamos recopilando el atributo expected_type de cada validador y almacenándolo en la variable de clase _types. Esto será útil más adelante cuando convertamos los datos de las filas a los tipos correctos.

  1. Ahora, agregaremos el método de clase from_row a la clase Structure. Este método nos permitirá crear una instancia de la clase a partir de una fila de datos, que podría ser una lista o una tupla.
@classmethod
def from_row(cls, row):
    """
    Create an instance from a data row (list or tuple)
    """
    rowdata = [func(val) for func, val in zip(cls._types, row)]
    return cls(*rowdata)

Así es cómo funciona este método:

  • Toma una fila de datos, que puede estar en forma de lista o tupla.
  • Convierte cada valor en la fila al tipo esperado utilizando la función correspondiente de la lista _types.
  • Luego crea y devuelve una nueva instancia de la clase utilizando los valores convertidos.
  1. Después de realizar estos cambios, guarda el archivo structure.py. Esto asegura que tus cambios en el código se conserven.

  2. Probemos nuestro método from_row para asegurarnos de que funcione como se espera. Crearemos una prueba simple utilizando la clase Stock. Ejecuta el siguiente comando en tu terminal:

cd ~/project
python3 -c "from stock import Stock; s = Stock.from_row(['GOOG', '100', '490.1']); print(s); print(f'Cost: {s.cost}')"

Deberías ver una salida similar a esta:

Stock('GOOG', 100, 490.1)
Cost: 49010.0

Observa que los valores de cadena '100' y '490.1' se convirtieron automáticamente a los tipos correctos (entero y flotante). Esto muestra que nuestro método from_row está funcionando correctamente.

  1. Finalmente, intentemos leer datos de un archivo CSV utilizando nuestro módulo reader.py. Ejecuta el siguiente comando en tu terminal:
cd ~/project
python3 -c "from stock import Stock; import reader; portfolio = reader.read_csv_as_instances('portfolio.csv', Stock); print(portfolio); print(f'Total value: {sum(s.cost for s in portfolio)}')"

Deberías ver una salida que muestre las acciones del archivo CSV:

[Stock('GOOG', 100, 490.1), Stock('AAPL', 50, 545.75), Stock('MSFT', 200, 30.47)]
Total value: 73444.0

El método from_row nos permite convertir fácilmente datos CSV en instancias de la clase Stock. Cuando se combina con la función read_csv_as_instances, tenemos una forma poderosa de cargar y trabajar con datos estructurados.

✨ Revisar Solución y Practicar

Adición de validación de argumentos de métodos

En Python, validar datos es una parte importante de escribir código robusto. En esta sección, llevaremos nuestra validación un paso más allá al validar automáticamente los argumentos de los métodos. El archivo validate.py ya incluye un decorador @validated. Un decorador en Python es una función especial que puede modificar otra función. El decorador @validated aquí puede verificar los argumentos de una función en contra de sus anotaciones. Las anotaciones en Python son una forma de agregar metadatos a los parámetros y valores de retorno de una función.

Modifiquemos nuestro código para aplicar este decorador a métodos con anotaciones:

  1. Primero, necesitamos entender cómo funciona el decorador validated. Abre el archivo validate.py para revisarlo:
code ~/project/validate.py

El decorador validated utiliza las anotaciones de la función para validar los argumentos. Antes de permitir que la función se ejecute, verifica cada argumento en contra de su tipo de anotación. Por ejemplo, si un argumento está anotado como un entero, el decorador se asegurará de que el valor pasado sea en realidad un entero.

  1. Ahora, modificaremos la función validate_attributes en structure.py para envolver los métodos con anotaciones con el decorador validated. Esto significa que cualquier método con anotaciones en la clase tendrá sus argumentos validados automáticamente. Abre el archivo structure.py:
code ~/project/structure.py
  1. Actualiza la función validate_attributes:
def validate_attributes(cls):
    """
    Class decorator that:
    1. Extracts Validator instances and builds _fields and _types lists
    2. Applies @validated decorator to methods with annotations
    """
    ## Import the validated decorator
    from validate import validated

    ## Process validator descriptors
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Set _types based on validator expected_types
    cls._types = [getattr(val, 'expected_type', lambda x: x) for val in validators]

    ## Apply @validated decorator to methods with annotations
    for name, val in vars(cls).items():
        if callable(val) and hasattr(val, '__annotations__'):
            setattr(cls, name, validated(val))

    ## Create initialization method
    cls.create_init()

    return cls

Esta función actualizada ahora hace lo siguiente:

  1. Procesa los descriptores de validación como antes. Los descriptores de validación se utilizan para definir reglas de validación para los atributos de la clase.

  2. Encuentra todos los métodos con anotaciones en la clase. Las anotaciones se agregan a los parámetros de los métodos para especificar el tipo esperado del argumento.

  3. Aplica el decorador @validated a esos métodos. Esto asegura que los argumentos pasados a estos métodos se validen de acuerdo con sus anotaciones.

  4. Guarda el archivo después de hacer estos cambios. Guardar el archivo es importante porque se asegura de que nuestras modificaciones se almacenen y se puedan utilizar más tarde.

  5. Ahora, actualicemos el método sell en la clase Stock para incluir una anotación. Las anotaciones ayudan a especificar el tipo esperado del argumento, que será utilizado por el decorador @validated para la validación. Abre el archivo stock.py:

code ~/project/stock.py
  1. Modifica el método sell para incluir una anotación de tipo:
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

    @property
    def cost(self):
        return self.shares * self.price

    def sell(self, nshares: PositiveInteger):
        self.shares -= nshares

El cambio importante es agregar : PositiveInteger al parámetro nshares. Esto le dice a Python (y a nuestro decorador @validated) que valide este argumento utilizando el validador PositiveInteger. Entonces, cuando llamamos al método sell, el argumento nshares debe ser un entero positivo.

  1. Vuelve a ejecutar las pruebas para verificar que todo siga funcionando. Ejecutar pruebas es una buena manera de asegurarse de que nuestros cambios no hayan roto ninguna funcionalidad existente.
cd ~/project
python3 teststock.py

Deberías ver que todas las pruebas pasan:

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK
  1. Probemos nuestra nueva validación de argumentos. Intentaremos llamar al método sell con argumentos válidos e inválidos para ver si la validación funciona como se espera.
cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); s.sell(25); print(s); try: s.sell(-25); except Exception as e: print(f'Error: {e}')"

Deberías ver una salida similar a:

Stock('GOOG', 75, 490.1)
Error: Bad Arguments
  nshares: must be >= 0

Esto muestra que nuestra validación de argumentos de métodos está funcionando. La primera llamada a sell(25) tiene éxito porque 25 es un entero positivo. Pero la segunda llamada a sell(-25) falla porque -25 no es un entero positivo.

Ahora has implementado un sistema completo para:

  1. Validar atributos de clase utilizando descriptores. Los descriptores se utilizan para definir reglas de validación para los atributos de la clase.
  2. Recopilar automáticamente información de campos utilizando decoradores de clase. Los decoradores de clase pueden modificar el comportamiento de una clase, como recopilar información de campos.
  3. Convertir datos de filas en instancias. Esto es útil cuando se trabaja con datos de fuentes externas.
  4. Validar argumentos de métodos utilizando anotaciones. Las anotaciones ayudan a especificar el tipo esperado del argumento para la validación.

Esto demuestra el poder de combinar descriptores y decoradores en Python para crear clases expresivas y auto-validantes.

✨ Revisar Solución y Practicar

Resumen

En este laboratorio, has aprendido cómo combinar las potentes características de Python para crear código limpio y auto - validante. Has dominado conceptos clave como el uso de descriptores para la validación de atributos, la creación de decoradores de clase para la automatización de la generación de código y la aplicación automática de decoradores a través de la herencia.

Estas técnicas son herramientas poderosas para crear código Python robusto y mantenible. Te permiten expresar claramente los requisitos de validación y aplicarlos en todo tu código base. Ahora puedes aplicar estos patrones en tus propios proyectos de Python para mejorar la calidad del código y reducir el código repetitivo.