Class Abstraction / Abstracción de Clases - Coding Basics #14
@abstractmethod def SayHello(Post)
In this article you'll find:
- Introduction
- What is abstraction?
- What does abstraction look like in code?
- Using abstract methods with parameters
- Abstract Properties
In the previous article, where we talked about class encapsulation, I talked about the need that some programmers may have to hide their code from malicious users who want to modify it.
Well now, we continue with the purpose of hiding code, only for different reasons. Now, we will seek to hide code from our users to reduce the complexity of their experience, allowing them to see what the program does, but not how it does it.
This is where the concept of abstraction comes in, which will allow us to not only create a less complex program for the user, but also increase the program's efficiency.
That said,
Let's get started!
What is abstraction?
In object-oriented programming, abstraction is used to hide the basics of a function or method from the user. Thus the user will only see the method's functionality (what it can do) but will still not know the internal details of the definition.
But, how is this done?
In classes, we must create the method initially, just defining it and placing no value for its implementation, just a pass. Then, when creating child classes, we can assign the implementation as it best suits our needs.
Looking at an example for the sound of different animals, we will create a class with an abstract method for the sound. The child classes will be the animals; according to these, the sound varies by means of the methods.
Thus, we can see that abstraction takes place, where the abstract method of the parent class is redefined to be implemented in the child classes. In this way, we hide the non-relevant information of the parent class and take the function definition and apply it to our purposes.
We know how this works in principle but what does this look like in code?
What does abstraction look like in code?
Since we can consider an abstract class to be any class that contains one or more abstract methods, we can assume that defining the class and the method will be enough. However, before doing this we must import the ABC or Abstract Base Classes module (we will talk more about modules in the future).
from abc import ABC
By means of ABC, which is a class in Itself, we will be able to inherit the characteristics that allow us to create abstract methods. Then, the syntax will be the following:
class ExampleClass(ABC):
def abstractmethod(self):
pass
With this, we will have defined the class and the abstract method. However, for the abstraction to be complete, it will need to be implemented in different ways for each child class:
from abc import ABC
class ExampleClass(ABC):
def abstractmethod(self):
pass
class ChildClass1(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 1')
class ChildClass2(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 2')
Now, if we create objects and call the method:
object_1 = ChildClass1()
object_2 = ChildClass2()
object_1.abstractmethod()
object_2.abstractmethod()
>>>
Abstract method implementation 1
Abstract method implementation2
This is one way to do it. However, the best practice will always be to use the @abstractmethod decorator (more about decorators in upcoming articles), allowing us to assign which methods will be abstract. First, we must import abstractmethod from the abc library and then apply the decorator to our method:
from abc import ABC, abstractmethod
class ExampleClass(ABC):
@abstractmethod
def abstractmethod(self):
pass
class ChildClass1(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 1')
class ChildClass2(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 2')
object_1 = ChildClass1()
object_2 = ChildClass2()
object_1.abstractmethod()
object_2.abstractmethod()
Thus, we would get the same result.
Abstract method implementation 1
Abstract method implementation 2
Whenever we create an object to use an abstract method, we must be sure to use the child classes and give an implementation to the methods. In case we try to create an object for the parent class and try to invoke the method, we will get the following error:
TypeError: Can't instantiate abstract class ExampleClass with abstract method abstractmethod
Using abstract methods with parameters
If we want to create abstract methods containing parameters, we use the abstractmethod decorator, where, when we define the function, we add a parameter. For example:
class Plane(ABC):
@abstractmethod
def Flight(self,hour):
pass
class Plane1(Plane):
def Flight(self,hour):
print(f "The flight left at {hour}")
US_Canada = Plane1()
US_Canada.Flight('12:00 am')
Here, we can see that it is as easy as adding a parameter to the abstract method and redefining using the same format to achieve the result we want. Now, what if we want to use abstract attributes as well?
Abstract Properties
Sometimes, in addition to methods, we want to use abstract properties in order to contribute to the efficiency and comprehension of the program. To do this, in addition to the @abstractmethod decorator we use
@property to define a method that represents the attribute in the parent class. For example:
class Career(ABC):
@abstractmethod
def __init__(self,title):
self._title = title
@property
@abstractmethod
def title(self):
pass
@title.setter
@abstractmethod
def title(self,value):
pass
This will be the parent class, where if we go back to the protected classes, the Getter and Setter, concepts that we observed in this article, we can notice that using the decorators we create a property with abstract method, which will refer to the title.
When we use @property, we define the title method, with which we will return the value of the attribute in the child function, as well as a setter, which will allow us to verify if the encapsulation is being carried out.
Thus, when creating a derived or child class:
class Engineer(Career):
def __init__(self,title):
self._title = title
@property
def title(self):
return self._title
@title.setter
def name(self,value):
self._title = value
Thus, when creating a derived or child class:
class Engineer(Career):
def __init__(self,title):
self._title = title
@property
def title(self):
return self._title
@title.setter
def name(self,value):
self._title = value
Where we finally implement the property, returning the value of the private attribute title. Finally, by using the setter we make sure that the property works by setting the parameter value to _title.
This way, when creating an object of the derived class:
Electronic = Engineer('Electronics Engineer')
print(Electronic.title)
>>> Electronics Engineer
And so we will apply abstraction with properties.
Abstraction is a very useful tool when it comes to hiding information that is not useful or too complex for the user to understand. Now, with this knowledge, you will be able to control the user experience at will.
We are almost done with the key concepts of object-oriented programming, which is why we will see some exercises in order to put the acquired knowledge into practice. All in future editions of Coding Basics ;)
Thank you for your support and good luck!
@abstractmethod def SayHello(Post)
In this article you'll find:
- Introducción
- ¿Qué es abstracción?
- ¿Cómo luce la abstracción en código?
- Usando métodos abstractos con parámetros
- Propiedades Abstractas
En el artículo anterior, donde hablamos del encapsulamiento de clases, hablé de la necesidad que algunos programadores puedan tener por ocultar su código de usuarios malintencionados que lo quieran modificar.
Pues ahora, seguimos con la finalidad de ocultar código, solo que por razones distintas. Ahora, buscaremos esconder código de nuestros usuarios para reducir la complejidad de su experiencia, permitiéndoles ver que hace el programa, más no como lo hace.
Es aquí donde el concepto de abstracción se hace presente, lo cual nos permitirá no solo crear un programa menos complejo para el usuario, sino que también aumentará la eficiencia de este.
Dicho esto:
¡Comencemos!
¿Qué es abstracción?
En programación orientada a objetos, la abstracción se usa para ocultar al usuario la definición básica de una función o método. Así el usuario solo verá las funcionalidades del método (Lo que puede hacer) pero seguirá sin saber los detalles internos de la definición.
Pero, ¿Como se lleva esto a cabo?
En clases, debemos de crear el método inicialmente, solo definiéndolo y colocando ningún valor para su implementación, simplemente un pass. Luego, al crear clases hijas, podemos asignar la implementación como más se ajuste a nuestras necesidades.
Viendo un ejemplo para el sonido de distintos animales, crearemos una clase con un método abstracto para el sonido. Las clases hijas serán los animales y de acuerdo a estos, el sonido varía por medio de los métodos.
Así, podemos ver que se lleva a cabo la abstracción, donde el método abstracto de la clase padre se redefine para ser implementado en las clases hijas. De esta forma, ocultamos la información no relevante de la clase padre y tomamos la definición de la función para aplicarla a nuestros fines.
Sabemos como esto funciona en principio pero ¿Cómo se ve esto en código?
¿Cómo luce la abstracción en código?
Ya que podemos considerar una clase abstracta a toda aquella que contenga a uno o más métodos abstractos, podemos suponer que con definir la clase y el método será suficiente. Sin embargo, antes de hacer esto debemos de importar el módulo ABC o Abstract Base Classes (Hablaremos más sobre los módulos en el futuro).
from abc import ABC
Por medio de ABC, que en si es una clase, podremos heredar las características que nos dejan crear métodos abstractos. Entonces, la sintaxis será la siguiente:
class ExampleClass(ABC):
def abstractmethod(self):
pass
Con esto, habremos definido la clase y el método abstracto. Sin embargo, para que la abstracción se complete, hará falta la implementacion de maneras distintas para cada clase hija:
from abc import ABC
class ExampleClass(ABC):
def abstractmethod(self):
pass
class ChildClass1(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 1')
class ChildClass2(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 2')
Ahora, si creamos objetos y llamamos al método:
object_1 = ChildClass1()
object_2 = ChildClass2()
object_1.abstractmethod()
object_2.abstractmethod()
>>>
Abstract method implementation 1
Abstract method implementation2
Esto es una forma de hacerlo. Sin embargo, la mejor práctica siempre será el uso del decorador @abstractmethod (más sobre decoradores en próximos artículos), que nos permitirá asignar cual de los métodos será abstracto. Primero, debemos de importar abstractmethod desde la librería abc y luego aplicar el decorador a nuestro método:
class ExampleClass(ABC):
@abstractmethod
def abstractmethod(self):
pass
class ChildClass1(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 1')
class ChildClass2(ExampleClass):
def abstractmethod(self):
print('Abstract method implementation 2')
object_1 = ChildClass1()
object_2 = ChildClass2()
object_1.abstractmethod()
object_2.abstractmethod()
Así, obtendríamos el mismo resultado.
Abstract method implementation 1
Abstract method implementation 2
Siempre que creemos un objeto para usar un método abstracto, debemos de asegurarnos de usar las clases hijas y darle una implementación a los métodos. En caso de que trataramos de crear un objeto para la clase padre y trataramos de invocar al método, nos saltaría el siguiente error:
TypeError: Can't instantiate abstract class ExampleClass with
abstract method abstractmethod
Métodos Abstractos con Parámetros
Si queremos crear métodos abstractos que contengan parámetros, nos valemos del decorador abstractmethod, donde, cuando definamos la función, añadimos un parámetro. Por ejemplo:
class Plane(ABC):
@abstractmethod
def Flight(self,hour):
pass
class Plane1(Plane):
def Flight(self,hour):
print(f"The flight left at {hour}")
US_Canada = Plane1()
US_Canada.Flight('12:00 am')
Aquí, podemos ver que es tan fácil como añadir un parámetro al método abstracto y redefinir usando el mismo formato para lograr el resultado que queremos. Ahora, ¿Qué pasaría si queremos usar atributos abstractos también?
Propiedades Abstractas
A veces, además de métodos, deseamos usar propiedades abstractas en orden de contribuir a la eficiencia y a la comprensión del programa. Para hacer esto, además del decorador @abstractmethod usamos
@property para definir un método que represente al atributo en la clase padre. Por ejemplo:
class Career(ABC):
@abstractmethod
def __init__(self,title):
self._title = title
@property
@abstractmethod
def title(self):
pass
@title.setter
@abstractmethod
def title(self,value):
pass
Esta será la clase padre, donde si volvemos a las clases protegidas, los Getter y Setter, conceptos que observamos en este artículo, podremos notar que por medio de los decoradores creamos una propiedad con abstract method, que se referirá al título.
Cuando usamos @property, definimos el método de title, con el que retornaremos el valor del atributo en la función hija, así como un setter, que nos permitirá verificar si se está llevando a cabo la encapsulación.
Así, al crear una clase derivada o hija:
class Engineer(Career):
def __init__(self,title):
self._title = title
@property
def title(self):
return self._title
@title.setter
def name(self,value):
self._title = value
Donde finalmente implementamos la propiedad, retornando el valor del atributo privado title. Finalmente, al usar el setter nos aseguramos de que funcione la propiedad al colocarle el valor de parámetro a _title.
De esta forma, al crear un objeto de la clase derivada:
Electronic = Engineer('Electronics Engineer')
print(Electronic.title)
>>> Electronics Engineer
Y así aplicaremos la abstracción con propiedades.
La abstracción es una herramienta de gran utilidad a la hora de ocultar información no util o demasiado compleja para la comprensión del usuario. Ahora, con este conocimiento, podrás controlar la experiencia del usuario a mayor voluntad
Ya casi terminamos con los conceptos clave de la programación orientada a objetos, razón por la cual veremos algunos ejercicios en orden de poner en práctica los conocimientos adquiridos. Todo en próximas ediciones de Coding Basics ;)
¡Gracias por tu apoyo y buena suerte!