Link Search Menu Expand Document

Programaci贸n Orientada a Objetos

Antes de nada, empecemos con una introducci贸n b谩sica a la Programaci贸n Orientada a Objetos POO o OOP en ingl茅s. Se trata de un paradigma de programaci贸n introducido en los a帽os 1970s, pero que no se hizo popular hasta a帽os m谩s tarde.

Este modo o paradigma de programaci贸n nos permite organizar el c贸digo de una manera que se asemeja bastante a como pensamos en la vida real, utilizando las famosas clases. Estas nos permiten agrupar un conjunto de variables y funciones que veremos a continuaci贸n.

Cosas de lo m谩s cotidianas como un perro o un coche pueden ser representadas con clases. Estas clases tienen diferentes caracter铆sticas, que en el caso del perro podr铆an ser la edad, el nombre o la raza. Llamaremos a estas caracter铆sticas, atributos.

Por otro lado, las clases tienen un conjunto de funcionalidades o cosas que pueden hacer. En el caso del perro podr铆a ser andar o ladrar. Llamaremos a estas funcionalidades m茅todos.

Por 煤ltimo, pueden existir diferentes tipos de perro. Podemos tener uno que se llama Toby o el del vecino que se llama Laika. Llamaremos a estos diferentes tipos de perro objetos. Es decir, el concepto abstracto de perro es la clase, pero Toby o cualquier otro perro particular ser谩 el objeto.

La programaci贸n orientada a objetos est谩 basada en 6 principios o pilares b谩sicos:

Motivaci贸n

Una vez explicada la programaci贸n orientada a objetos puede parecer bastante l贸gica, pero no es algo que haya existido siempre, y de hecho hay muchos lenguajes de programaci贸n que no la soportan.

En parte surgi贸 debido a la creciente complejidad a la que los programadores se iban enfrentando conforme pasaban los a帽os. En el mundo de la programaci贸n hay gran cantidad de aplicaciones que realizan tareas muy similares y es importante identificar los patrones que nos permiten no reinventar la rueda. La programaci贸n orientada a objetos intentaba resolver esto.

Uno de los primeros mecanismos que se crearon fueron las funciones, que permiten agrupar bloques de c贸digo que hacen una tarea espec铆fica bajo un nombre. Algo muy 煤til ya que permite tambi茅n reusar esos m贸dulos o funciones sin tener que copiar todo el c贸digo, tan solo la llamada.

Las funciones resultaron muy 煤tiles, pero no eran capaces de satisfacer todas las necesidades de los programadores. Uno de los problemas de las funciones es que s贸lo realizan unas operaciones con unos datos de entrada para entregar una salida, pero no les importa demasiado conservar esos datos o mantener alg煤n tipo de estado. Salvo que se devuelva un valor en la llamada a la funci贸n o se usen variables globales, todo lo que pasa dentro de la funci贸n queda olvidado, y esto en muchos casos es un problema.

Imaginemos que tenemos un juego con naves espaciales movi茅ndose por la pantalla. Cada nave tendr谩 una posici贸n (x,y) y otros par谩metros como el tipo de nave, su color o tama帽o. Sin hacer uso de clases y POO, tendremos que tener una variable para cada dato que queremos almacenar: coordenadas, color, tama帽o, tipo. El problema viene si tenemos 10 naves, ya que nos podr铆amos juntar con un n煤mero muy elevado de variables. Todo un desastre.

En el mundo de la programaci贸n existen tareas muy similares al ejemplo con las naves, y en respuesta a ello surgi贸 la programaci贸n orientada a objetos. Una herramienta perfecta que permite resolver cierto tipo de problemas de una forma mucho m谩s sencilla, con menos c贸digo y m谩s organizado. Agrupa bajo una clase un conjunto de variables y funciones, que pueden ser reutilizadas con caracter铆sticas particulares creando objetos.

Definiendo clases

Vista ya la parte te贸rica, vamos a ver como podemos hacer uso de la programaci贸n orientada a objetos en Python. Lo primero es crear una clase, para ello usaremos el ejemplo de perro.

# Creando una clase vac铆a
class Perro:
    pass

Se trata de una clase vac铆a y sin mucha utilidad pr谩ctica, pero es la m铆nima clase que podemos crear. N贸tese el uso del pass que no hace realmente nada, pero dar铆a un error si despu茅s de los : no tenemos contenido.

Ahora que tenemos la clase, podemos crear un objeto de la misma. Podemos hacerlo como si de una variable normal se tratase. Nombre de la variable igual a la clase con (). Dentro de los par茅ntesis ir铆an los par谩metros de entrada si los hubiera.

# Creamos un objeto de la clase perro
mi_perro = Perro()

Definiendo atributos

A continuaci贸n vamos a a帽adir algunos atributos a nuestra clase. Antes de nada es importante distinguir que existen dos tipos de atributos:

  • Atributos de instancia: Pertenecen a la instancia de la clase o al objeto. Son atributos particulares de cada instancia, en nuestro caso de cada perro.
  • Atributos de clase: Se trata de atributos que pertenecen a la clase, por lo tanto ser谩n comunes para todos los objetos.

Empecemos creando un par de atributos de instancia para nuestro perro, el nombre y la raza. Para ello creamos un m茅todo __init__ que ser谩 llamado autom谩ticamente cuando creemos un objeto. Se trata del constructor.

class Perro:
    # El m茅todo __init__ es llamado al crear el objeto
    def __init__(self, nombre, raza):
        print(f"Creando perro {nombre}, {raza}")

        # Atributos de instancia
        self.nombre = nombre
        self.raza = raza

Ahora que hemos definido el m茅todo init con dos par谩metros de entrada, podemos crear el objeto pasando el valor de los atributos. Usando type() podemos ver como efectivamente el objeto es de la clase Perro.

mi_perro = Perro("Toby", "Bulldog")
print(type(mi_perro))
# Creando perro Toby, Bulldog
# <class '__main__.Perro'>

Seguramente te hayas fijado en el self que se pasa como par谩metro de entrada del m茅todo. Es una variable que representa la instancia de la clase, y deber谩 estar siempre ah铆.

El uso de __init__ y el doble __ no es una coincidencia. Cuando veas un m茅todo con esa forma, significa que est谩 reservado para un uso especial del lenguaje. En este caso ser铆a lo que se conoce como constructor. Hay gente que llama a estos m茅todos m谩gicos.

Por 煤ltimo, podemos acceder a los atributos usando el objeto y .. Por lo tanto.

print(mi_perro.nombre) # Toby
print(mi_perro.raza)   # Bulldog

Hasta ahora hemos definido atributos de instancia, ya que son atributos que pertenecen a cada perro concreto. Ahora vamos a definir un atributo de clase, que ser谩 com煤n para todos los perros. Por ejemplo, la especie de los perros es algo com煤n para todos los objetos Perro.

class Perro:
    # Atributo de clase
    especie = 'mam铆fero'

    # El m茅todo __init__ es llamado al crear el objeto
    def __init__(self, nombre, raza):
        print(f"Creando perro {nombre}, {raza}")

        # Atributos de instancia
        self.nombre = nombre
        self.raza = raza

Dado que es un atributo de clase, no es necesario crear un objeto para acceder al atributos. Podemos hacer lo siguiente.

print(Perro.especie)
# mam铆fero

Se puede acceder tambi茅n al atributo de clase desde el objeto.

mi_perro = Perro("Toby", "Bulldog")
mi_perro.especie
# 'mam铆fero'

De esta manera, todos los objetos que se creen de la clase perro compartir谩n ese atributo de clase, ya que pertenecen a la misma.

Definiendo m茅todos

En realidad cuando usamos __init__ anteriormente ya est谩bamos definiendo un m茅todo, solo que uno especial. A continuaci贸n vamos a ver como definir m茅todos que le den alguna funcionalidad interesante a nuestra clase, siguiendo con el ejemplo de perro.

Vamos a codificar dos m茅todos, ladrar y caminar. El primero no recibir谩 ning煤n par谩metro y el segundo recibir谩 el n煤mero de pasos que queremos andar. Como hemos indicado anteriormente self hace referencia a la instancia de la clase. Se puede definir un m茅todo con def y el nombre, y entre () los par谩metros de entrada que recibe, donde siempre tendr谩 que estar self el primero.

class Perro:
    # Atributo de clase
    especie = 'mam铆fero'

    # El m茅todo __init__ es llamado al crear el objeto
    def __init__(self, nombre, raza):
        print(f"Creando perro {nombre}, {raza}")

        # Atributos de instancia
        self.nombre = nombre
        self.raza = raza

    def ladra(self):
        print("Guau")

    def camina(self, pasos):
        print(f"Caminando {pasos} pasos")

Por lo tanto si creamos un objeto mi_perro, podremos hacer uso de sus m茅todos llam谩ndolos con . y el nombre del m茅todo. Como si de una funci贸n se tratase, pueden recibir y devolver argumentos.

mi_perro = Perro("Toby", "Bulldog")
mi_perro.ladra()
mi_perro.camina(10)

# Creando perro Toby, Bulldog
# Guau
# Caminando 10 pasos

Si te ha parecido 煤til este post, tal vez te interese: