Biblioteca Online : ¡La Suscripción ENI por 9,90 € el primer mes!, con el código PRIMER9. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Python 3
  3. Modelo de objetos
Extrait - Python 3 Los fundamentos del lenguaje (4ª edición)
Extractos del libro
Python 3 Los fundamentos del lenguaje (4ª edición) Volver a la página de compra del libro

Modelo de objetos

Todo es un objeto

1. Principios

a. Qué sentido dar a «objeto»

Python es un lenguaje que utiliza varios paradigmas y, entre ellos, el paradigma orientado a objetos. Este se elaboró durante los años 1970 y es, ante todo, un concepto. Un objeto representa:

  • un objeto físico:

  • parcela de terreno, bien inmueble, apartamento, propietario, inquilino...;

  • coche, piezas de un coche, conductor, pasajero...;

  • biblioteca, libro, página de un libro...;

  • dispositivo de hardware, robot...;

  • un objeto informático:

  • archivo (imagen, documento de texto, sonido, vídeo...);

  • servicio (servidor, cliente, sitio de Internet, servicio web...);

  • un flujo de datos, pool de conexiones...;

  • un concepto:

  • portador de alguna noción que pueda compartir;

  • secuenciador, ordenador, analizador de datos...

Aprovechamos para llamar la atención del lector sobre ciertos aspectos cognitivos: a partir del momento en que se modelizan personas como objetos, es fácil olvidar que detrás del código hay seres vivos que piensan, y cuya libertad puede ser limitada por las elecciones que se hacen sobre la manera de modelizar, la cantidad o la calidad de las informaciones que se decide tratar o conservar.

Aquí vemos un ejemplo muy simple y concreto: un gestor de horarios que solo permite crear franjas cada media hora puede tener una repercusión real sobre el funcionamiento de un servicio que necesita una granularidad más fina. Por lo tanto, influye de manera muy negativa en los usuarios que, antes de la llegada del software, tenían horarios que permitían más libertad.

Además, a partir del momento en que almacena datos de sus usuarios, es responsable de su conservación y seguridad; por eso tiene que asegurarse de que no se puedan filtrar, robar o incluso corromper.

Hay organismos que permiten dar una visión correcta de las reglas básicas que se deben seguir para tratar datos de este tipo, y también legislaciones, como el RGPD, que a su vez determinan algunos principios útiles.

Para modelizar como objeto, es necesario seguir algunos principios.

Uno de los principios es la encapsulación de datos. Esto significa que cada objeto posee en su seno no solo los datos que lo describen y que contiene (bajo la forma de atributos), sino también el conjunto de métodos necesarios para gestionar sus propios datos (modificación...

Otras herramientas de la programación orientada a objetos

1. Principios

En Python, los aspectos esenciales de la programación orientada a objetos se basan en la correcta declaración de las clases, en la flexibilidad del propio lenguaje, que permite acoplar las clases, las instancias, sus atributos y sus métodos tal y como se desee, y en otras cualidades desarrolladas en los dos capítulos anteriores.

Conocer lo expuesto en la sección Todo es un objeto nos permite escribir fácilmente componentes eficaces y arquitecturizarlos conforme a nuestras expectativas. Se trata de funcionalidades ligeras, no restrictivas, muy ágiles y suficientes para responder a todos los casos de uso.

Para los debutantes, esto es suficiente e incluso en muchos casos, para aquellos programadores más experimentados, raras son las veces en las que es necesario utilizar otros conceptos.

Pero Python es un lenguaje muy completo y permite ofrecer funcionalidades más complejas y más completas sin tener, por ello, que imponerlas y hacer su modelo de objetos restrictivo. La libertad que tiene el desarrollador para seleccionar la solución es una regla de su filosofía, pero libertad de elección no significa únicamente «no existen restricciones», significa también un panel de opciones importante y útil.

2. Interfaces

Ahora que sabemos escribir clases, organizarlas, gestionar sus atributos y métodos, es momento de hacerlas dialogar entre sí. Una de las problemáticas consiste en determinar con qué tipo de clase es posible interactuar.

Para ello, Python se fundamenta en el principio de «duck typing». Si funciona como un pato y anda como un pato, entonces será un pato. Dicho de otro modo, si un objeto posee los métodos necesarios, entonces este objeto debe ser el que esperamos.

>>> import csv 
>>> csv.reader(file) 

El objeto file es una clase que interactúa con reader, pero file no puede ser cualquier clase, del mismo modo que reader la utiliza de una forma determinada.

>>> class File:  
...     pass  
  
...   
>>> file = File()  
>>> csv.reader(file)  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
TypeError: argument...

Funciones principales y primitivas asociadas

1. Personalización

a. Clases

Es posible personalizar las clases utilizando correctamente el método especial __new__ y las metaclases, que hemos visto antes en este capítulo. En este sentido, Python 3 ha mejorado bastante, simplificando y homogeneizando su comportamiento respecto a la versión anterior.

Este método especial es un método de clase (su primer argumento es la clase). Es este método el que crea una instancia de la clase en curso e invoca a su método __init__, que es un método de instancia. Los demás argumentos que se pasan a los dos métodos son idénticos.

La sobrecarga de __new__ permite, por tanto, personalizar la manera en que se crea la instancia, mientras que la sobrecarga de __init__ permite personalizar la propia instancia, colocando atributos, por ejemplo.

He aquí una demostración del orden en que se invocan los métodos:

>>> class A:  
...     def __new__(cls, info):  
...         print('A\tNew\t%s\t\t\t%s' % (cls, info))  
...         return object.__new__(cls, info)  
...     def __init__(self, info):  
...         print('A\tInit\t%s\t%s' % (self, info))  
...         return object.__init__(self, info)  
...   
>>> class B(A):  
...     def __new__(cls, info):  
...         print('B\tNew\t%s\t\t\t%s' % (cls, info))  
...         return A.__new__(cls, info)  
...     def __init__(self, info):  
...         print('B\tInit\t%s\t%s' % (self, info))  
...         return A.__init__(self, info)  
... 

He aquí el resultado de las llamadas:

>>> a = A('test 1')  
A  New   <class '__main__.A'>                       test 1  
A  Init  <__main__.A object at 0x261ea10>           test 1  
>>> b = B('test 2')  
B  New...