PyWombat

← Volver a artículos

Clases abstractas en Python

November 26, 2024

70 views

2 min de lectura

Una de las tantas cosas interesantes que posee Python, y en la mayoría de los caso para desapercibido, es sin duda alguna las clases abstractas. Sí, en Python, al igual que con otros lenguajes de programación, como lo puede ser Java, es posible definir clases abstractas.

Con las clases abstractas podemos definir una serie de métodos y propiedades que subclasses deben implementar de forma obligatoria. Esto nos ayuda a reforzar la estructura o comportamiento de las subclasses. Reduciendo así posibles errores en la herencia o el Polimorfismo.

Recordemos que las clases abstractas nos permiten resolver la pregunta del ¿Qué se debe hacer? y las clases que implementan dichas abstracciones responderán el ¿Cómo?.

Para poder poder implementar clases abstractas con Python haremos uso del módulo abc (Abstract Base Class). Veamos un par de ejemplos.

from abc import ABC, abstractmethod

class PaymentMethod(ABC):

    @abstractmethod
    def pay(self, amount):
        pass

En este ejemplo hemos definido la clase PaymentMethod que hereda de ABC. Al heredar de ABC indicamos que PaymentMethod es una clase abstracta, por lo cual No puede ser instanciada, solo heredada.

De igual forma hemos definido el método pay, el cual es decorado por abstractmethod. Dado que dicho método pretende resolver a la pregunta del ¿Qué se debe hacer? dejaremos su cuerpo vacío. Serán clases hijas quienes definan el comportamiento.

Si queremos usar dicha clase abstracta basta con heredar de ella.

class PayPalPaymentMethod(PaymentMethod):
    def pay(self, amount):
        print(f"Processing ${amount} via PayPal")

class StripePaymentMethod(PaymentMethod):
    def pay(self, amount):
        print(f"Processing ${amount} via Stripe")

processor = PayPalProcessor()
processor.pay(100)  # Output: Processing $100 via PayPal

En este caso nuestra clase abstracta posee un solo método abstracto, sin embargo es posible definir la N cantidad de métodos que deseemos. Aun que recuerda que: Entre más sea el nivel de abstracción menos atributos o métodos tendremos.

Aquí otro ejemplo.

from abc import ABC, abstractmethod

class Database(ABC):

    @abstractmethod
    def connect(self):
        pass

    @abstractmethod
    def disconnect(self):
        pass

class MySQLDatabase(Database):
    def connect(self):
        print("Connecting to MySQL")

    def disconect(self):
        print("Disconnect to MySQL")

db = MySQLDatabase()
db.connect()       # Output: Connecting to MySQL
db.disconnect()    # Output: Disconnecting from the database

Lo interesante de implementar clases abstractas es la seguridad que nos brindan, ya que si alguna clase hereda de una abstracción y no implementa todos sus métodos abstractos obtendremos un error.

class PSQLDatabase(Database):
    def connect(self):
        print("Connecting to MySQL")

>>> db = PSQLDatabase()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    db = PSQLDatabase()
TypeError: Can't instantiate abstract class PSQLDatabase with abstract method disconnect

Para este ejemplo tenemos la clase PSQLDatabase la cual solo implementa uno de los dos métodos abstractos de Database. Al intentar crear un objeto obtenemos un error.

Propiedades abstractas

Como lo mencionamos al principio del post, las clases abstractas también nos permiten definir propiedades. Para este haremos uso de abstractproperty.

from abc import ABC, abstractproperty

class Shape(ABC):
    @abstractproperty
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14 * self.radius ** 2

circle = Circle(10)
print(circle.area)

con abstractproperty seguiremos exactamente la misma regla. Si nuestra subclase no implemente la propiedad obtendremos un error.

Conclusión.

Listo, ahora ya lo sabes, en Python es posible implementar clase abstractas utilizando el módulo abc. Con las clases abstractas añadimos una capa más seguridad en la herencia pudiendo así evitar problemas de sobre escritura de métodos.