6.2 Objetos y Clases

6.2 Objetos y Clases

Hasta ahora hemos estado usando objetos de forma totalmente transparente, casi sin ser conscientes de ello. Pero, en realidad, todo en Python es un objeto, desde números a funciones. El lenguaje provee ciertos mecanismos para no tener que usar explícitamente técnicas de orientación a objetos.

Llegados a este punto, investigaremos en profundidad sobre la creación y manipulación de clases y objetos, y todas las operaciones que engloban este paradigma.[1]

6.2.1 Programación orientada a objetos

La programación orientada a objetos (POO) o en sus siglas inglesas OOP es una manera de programar que permite llevar al código mecanismos usados con entidades de la vida real.

Sus beneficios son los siguientes:

Encapsulamiento Permite empaquetar el código dentro de una unidad (objeto) donde se puede determinar el ámbito de actuación.

Abstracción Permite generalizar los tipos de objetos a través de las clases y simplificar el programa.

Herencia Permite reutilizar código al poder heredar atributos y comportamientos de una clase a otra.

Polimorfismo Permite crear múltiples objetos a partir de una misma pieza flexible de código.

6.2 Objetos y Clases

Figura 7: Beneficios de la Programación Orientada a Objetos

¿Qué es un objeto?

Un objeto es una estructura de datos personalizada que contiene datos y código:

6.2 Objetos y Clases

Un objeto representa una instancia única de alguna entidad a través de los valores de sus atributos e interactuan con otros objetos (o consigo mismos) a través de sus métodos.

6.2 Objetos y Clases

Figura 8: Analogía de atributos y métodos en un objeto «bicicleta»

¿Qué es una clase?

Para crear un objeto primero debemos definir la clase que lo contiene. Podemos pensar en la clase como el molde con el que crear nuevos objetos de ese tipo.

En el proceso de diseño de una clase hay que tener en cuenta – entre otros – el principio de responsabilidad única, intentando que los atributos y los métodos que contenga estén enfocados a un objetivo único y bien definido.

6.2.2 Creando objetos

Empecemos por crear nuestra primera clase. En este caso vamos a modelar algunos de los droides de la saga StarWars:

Para ello usaremos la palabra reservada class seguido del nombre de la clase:

6.2 Objetos y Clases

6.2 Objetos y Clases

Figura 9: Ejemplificación de creación de objetos a partir de una clase

6.2 Objetos y Clases

Figura 10: Droides de la saga StarWars

Consejo: Los nombres de clases se suelen escribir en formato CamelCase y en singular

Existen multitud de droides en el universo StarWars. Una vez que hemos definido la clase genérica podemos crear instancias/objetos (droides) concretos:

6.2 Objetos y Clases

Añadiendo atributos

Un atributo no es más que una variable, un nombre al que asignamos un valor, con la particularidad de vivir dentro de una clase o de un objeto.

Los atributos – por lo general – se suelen asignar durante la creación de un objeto, pero también es posible añadirlos a posteriori:

6.2 Objetos y Clases

Una vez creados, es muy sencillo acceder a los atributos:

6.2 Objetos y Clases

Hemos definido un droide «socio». Veremos a continuación que podemos trabajar con él de una manera totalmente natural:

6.2 Objetos y Clases

Añadiendo métodos

Un método es una función que forma parte de una clase o de un objeto. En su ámbito tiene acceso a otros métodos y atributos de la clase o del objeto al que pertenece.

La definición de un método (de instancia) es análoga a la de una función ordinaria, pero incorporando un primer parámetro self que hace referencia a la instancia actual del objeto.

Una de las acciones más sencillas que se pueden hacer sobre un droide es encenderlo o apagarlo. Vamos a implementar estos dos métodos en nuestra clase:

6.2 Objetos y Clases

Inicialización

Existe un método especial que se ejecuta cuando creamos una instancia de un objeto. Este método es_ init___ y nos permite asignar atributos y realizar operaciones con el objeto en el momento de su creación. También es ampliamente conocido como el constructor.

Veamos un ejemplo de este método con nuestros droides en el que únicamente guardaremos el nombre del droide como un atributo del objeto:

6.2 Objetos y Clases

Línea 2 Definición del constructor.

Línea 7 Creación del objeto (y llamada implícita al constructor)

Línea 9 Acceso al atributo name creado previamente en el constructor.

Ejercicio

Escriba una clase MobilePhone que represente un teléfono móvil.

Atributos:

  • manufacturer (cadena de texto)
  • screen_size (flotante)
  • num_cores (entero)
  • apps (lista de cadenas de texto)
  • status (0: apagado, 1: encendido)

Métodos:

  • __init__(self, manufacturer, screen_size, num_cores)
  • power_on(self)
  • power_off(self)
  • install_app(self, app)
  • uninstall_app(self, app)

Crear al menos una instancia (móvil) a partir de la clase creada y «jugar» con los métodos, visualizando cómo cambian sus atributos.

¿Serías capaz de extender el método install_app() para instalar varias aplicaciones a la vez?

6.2.3 Atributos

Acceso directo

En el siguiente ejemplo vemos que, aunque el atributo name se ha creado en el constructor de la clase, también podemos modificarlo desde «fuera» con un acceso directo:

6.2 Objetos y Clases

Propiedades

Como hemos visto previamente, los atributos definidos en un objeto son accesibles públicamente. Esto puede parecer extraño a personas desarrolladoras de otros lenguajes. En Python existe un cierto «sentido de responsabilidad» a la hora de programar y manejar este tipo de situaciones.

Una posible solución «pitónica» para la privacidad de los atributos es el uso de propiedades. La forma más común de aplicar propiedades es mediante el uso de decoradores:

  • @property para leer el valor de un atributo.
  • @name.setter para escribir el valor de un atributo.

Veamos un ejemplo en el que estamos ofuscando el nombre del droide a través de propiedades:

6.2 Objetos y Clases

6.2 Objetos y Clases

En cualquier caso, seguimos pudiendo acceder directamente a .hidden_name:

6.2 Objetos y Clases

Valores calculados

Una propiedad también se puede usar para devolver un valor calculado (o computado).

A modo de ejemplo, supongamos que la altura del periscopio de los droides astromecánicos se calcula siempre como un porcentaje de su altura. Veamos cómo implementarlo:

6.2 Objetos y Clases

6.2 Objetos y Clases

Consejo: La ventaja de usar valores calculados sobre simples atributos es que el cambio de valor en un atributo no asegura que actualicemos otro atributo, y además siempre podremos modificar directamente el valor del atributo, con lo que podríamos obtener efectos colaterales indeseados.

Ocultando atributos

Python tiene una convención sobre aquellos atributos que queremos hacer «privados» (u ocultos): comenzar el nombre con doble subguión __

6.2 Objetos y Clases

Atributos de clase

Podemos asignar atributos a las clases y serán heredados por todos los objetos instanciados de esa clase.

A modo de ejemplo, en un principio, todos los droides están diseñados para que obedezcan a su dueño. Esto lo conseguiremos a nivel de clase, salvo que ese comportamiento se sobreescriba:

6.2 Objetos y Clases

Publicaciones Similares