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.