Clases y objetos en Python

 ¿Qué son objetos y clases en Python?

En Python, al igual que en la gran mayoría de lenguajes de programación modernos, existe lo que se conoce como la programación orientada a objetos, lo que implica el uso de objetos y clases. Para aclarar el significado de objetos y clases, podemos decir que un objeto es un conjunto encapsulado de variables y funciones dentro de una entidad llamada objeto. Los objetos toman la estructura de sus variables y funciones de las clases, que son las que definen de manera genérica los tipos de datos que van a usar los objetos. Se podría decir entonces que las clases son el prototipo de estructura en lo que a variables y funciones se refiere de un objeto y el objeto en sí es la implementación encapsulada de esa estructura en un tipo de dato que puede recibir, procesar y devolver datos en si mismo. Los métodos y datos de una clase se denominan miembros de dicha clase.

Los objetos creados a partir de una clase, también llamados instancias o copias de una clase con valores reales, adquieren las siguientes propiedades: identidad, estado y comportamiento. Siendo la identidad el nombre de objeto, el estado sus variables y comportamiento sus métodos o funciones. Todos los objetos creados a partir de una clase comparten los métodos y variables de la clase pero los valores de cada objetos son únicos para cada uno de ellos.

Declaración de las clases.

Antes de empezar a trabajar con objetos en Python es necesario declarar su prototipo o lo que es lo mismo definir su clase, es como primero hacer el diseño de una casa en un plano antes de empezar su construcción. Las clases proveen los medios de encapsular en una sola declaración datos y funcionalidad juntos. Para definir una clase es necesario usar la palabra reservada CLASS. La sintaxis de la declaración de clases es como sigue:

CLASS <nombre_de_la_clase>:
    <declaraciones de datos propios de la clase>

Ejemplo:

class Vehiculo:
        pass
print("Clase Vehiculo creada satisfactoriamente")

Resultado:

Clase Vehiculo creada satisfactoriamente

Como podemos ver hemos creado una clase llamada vehículo sin ningún tipo de dato ni método, y no hemos instanciado dicha clase.  Nótese el uso de la palabra reservada PASS dentro del cuerpo de la clase a los efectos de poder ejecutar el programa en este punto sin necesidad de tener definidas las propiedades y métodos de la clase y aún así verificar que no haya ningún error en la declaración de la clase. El mensaje "Clase Vehículo creada satisfactoriamente" está únicamente para fines visuales y comprobar que el intérprete de Python haya creado correctamente la clase al llegar a la línea donde muestra este mensaje por pantalla.

Ahora que ya está creada la clase Vehiculo podemos empezar a crear objetos de esta clase. Para crear vehículos basta con usar el nombre del objeto y usar el operador de asignación "igual que" (=) seguido del nombre de la clase. Veamos el siguiente ejemplo:

class Vehiculo:
        pass

print("Clase Vehiculo creada satisfactoriamente")

Herbie = Vehiculo()
print("Objeto Herbie creado satisfactoriamente")

Resultado:

Clase Vehiculo creada satisfactoriamente
Objeto Herbie creado satisfactoriamente

Como podemos ver se ha creado un objeto llamado Herbie de la clase Vehiculo sin ningún dato ni método miembro. Agreguemos datos miembros de la clase Vehiculo para empezar a asignarle propiedades que el objeto instanciado pueda heredar. Para comprobar las propiedades del objeto basta con usar el comando PRINT() pasando como argumento el nombre del objeto instanciado seguido de un punto (.) y a continuación la propiedad a la que deseamos acceder.

import os
os.system("cls")

class Vehiculo:
        color = "Blanco"
        marca = "Volkswagen"
        modelo = "Beetle"
        carroceria = "Coupe"
        numero = "53"

Herbie = Vehiculo()

print("Datos miembros de la clase Vehiculo usados en el objeto Herbie:")

print(Herbie.color)
print(Herbie.marca)
print(Herbie.modelo)
print(Herbie.carroceria)
print(Herbie.numero)

Resultado:

Datos miembros de la clase Vehiculo usados en el objeto Herbie:
Blanco
Volkswagen
Beetle
Coupe
53

Como podemos ver el objeto Herbie instanciado de la clase Vehiculo obtiene las propiedades definidas en su clase. 

Procedamos ahora a agregar la primera funcionalidad para a case Vehiculo y que los objetos instanciados de ella puedan ejecutar: Para ello es necesario usar la palabra reservada DEF parara definir dentro de la clase el método o comportamiento que vamos a codificar. Recordemos que los métodos son las funciones miembros de una clase. La sintaxis de la palabra reservada DEF se puede ver con mas detalle en el apartado Funciones definidas por el usuario donde se explica a detalle su uso con ejemplos.

En el caso del uso de los métodos de clases la única diferencia es que las funciones miembros de una clase deben tener un primer parámetro extra en su declaración, el parámetro SELF. Python automáticamente le asigna un valor a éste parámetro, con lo cual no es necesario especificarlo. Otro punto importante a tomar en cuenta es que aunque el método no tome argumentos, aún así se debe especificar un argumento. Como es obvio, al invocar un método de una clase desde un objeto instanciado a dicha clase, dicho método se va a ejecutar sobre si mismo, con lo cual no es necesario especificar el nombre del objeto como parámetro. Sin embargo al llamar al método directamente como una función definida por el usuario es necesario especificar sobre que objeto va a operar dicho método, con lo cual se hace necesario incluir el nombre del objeto como parámetro. Veamos el siguiente ejemplo de ambos casos para ilustrarlo mejor:

import os
os.system("cls")

class Vehiculo:
        color = "Blanco"
        marca = "Volkswagen"
        modelo = "Beetle"
        carroceria = "Coupe"
        numero = "53"

        def acelerar(self):
                print("ruuuun ruuuun")
Herbie = Vehiculo()

print("Datos miembros de la clase Vehiculo usados en el objeto Herbie:")

print(Herbie.color)
print(Herbie.marca)
print(Herbie.modelo)
print(Herbie.carroceria)
print(Herbie.numero)

print("Ejecución del método acelerar invocándolo desde el objeto")
Herbie.acelerar()
print("Ejecución del método acelerar invocándolo desde la clase")
Vehiculo.acelerar(Herbie)

Resultado:

Datos miembros de la clase Vehiculo usados en el objeto Herbie:
Blanco
Volkswagen
Beetle
Coupe
53
Ejecución del método acelerar invocándolo desde el objeto
ruuuun ruuuun
Ejecución del método acelerar invocándolo desde la clase
ruuuun ruuuun

En este ejemplo hemos hecho uso de la palabra reservada SELF, la cual hace referencia al objeto en sí mismo, o lo que es lo mismo a la instancia perteneciente a la clase. Es importante destacar que es el primer parámetro obligatorio de la definición de métodos.

Hemos creado un método miembro de la clase Vehiculo que al ser invocado desde un objeto instanciado de su clase muestra por pantalla un mensaje diciendo "ruuun ruuuuun" sin necesidad de pasarle el nombre del objeto como parámetro ya que Python sabe que se trata del mismo objeto instanciado. Sin embargo en la línea de código desde donde se llama directamente al método de la clase Vehiculo se hace necesario especificar el parámetro del nombre del objeto, en este caso el valor del argumento es "Herbie", ya que ademas es el único objeto creado hasta ahora. Este proceso de creación de objetos es lo que se conoce como instanciación de una clase ya que se están creando instancias de una clase. Como nota adicional es importante mencionar que también algunos autores hacen referencia a este procedimiento como ejemplarización de clase.

Otro ejemplo de uso de métodos de una clase

Supongamos que tenemos una propiedad de una clase que define el estado en que se encuentra el vehículo en un momento determinado, por ejemplo: rodando o detenido, y deseamos crear un método que permita cambiar esta propiedad haciendo que el vehículo pase de estar  detenido que sería su estado inicial por defecto, a rodando. Veamos como quedaría con un ejemplo:

class automovil():
        color='Rojo'
        puertas='5'
        marca ='Ford'
        modelo='Focus'
        peso=1384
        largo=4.38
        ancho=1.82
        estado='Detenido'

        def arrancar(self):          
                print('Arrancando')    
                self.estado='Rodando'

auto1=automovil()
print(f'El vehículo auto1 esta en este momento: {auto1.estado}')

auto1.arrancar()

print(f'El vehículo auto1 está en este momento: {auto1.estado}')

Resultado:

El vehículo auto1 esta en este momento: Detenido
Arrancando
El vehículo auto1 está en este momento: Rodando

Como podemos ver el estado antes de ejecutar el método arrancar() de la clase automovil(), es 'Detenido'. Sin embargo esta propiedad se pudo modificar a través de la ejecución del dicho método, la cual recibió como argumento el nombre auto1 en el parámetro self al ser invocado desde el objeto mismo con el uso de la sintaxis de la nomenclatura de punto.

Tipos de métodos de las clases.

Existen 2 tipos de métodos, los métodos definidos por el usuario y los métodos especiales. Ya hemos visto en este mismo apartado los métodos de las clases definidos por el usuario, ahora bien los métodos especiales son los métodos ya incorporados en Python para cumplir una función específica preestablecida que pertenecen de forma nativa al super objeto OBJECT. Es importante destacar que no es necesario usar todos los métodos especiales para que un programa en Python funcione, de hecho lo recomendable es usar solamente los necesarios. Algunos métodos especiales son utilizados de manera automática al invocar las funciones incorporadas en Python de manera automática, incluso es posible no usar ningún método especial si no es requerido por las exigencias de la aplicación que se esté desarrollando. en todo caso, los métodos especiales siempre están al alcance de la mano para su uso dentro de nuestras definiciones de clases siempre y cuando se use la sintaxis adecuada.

Es importante destacar en este punto que en Python existe una clase que jerárquicamente esta por encima de todas las demás clases y las contiene a ellas, adicionalmente todas las clases creadas en Python heredan de manera automática las propiedades y métodos de esta la superclase OBJECT ya que Python automáticamente las considera a todas hijas de dicha superclase. Con lo cual todas las clases que creemos van a tener las propiedades y métodos que le definamos mas los heredados de la superclase OBJECT, lo cual implica que los objetos instanciados de dichas clases también tendrán dichas propiedades y métodos por herencia. Esta superclase no tiene atributos propios heredables, pero sí métodos genéricos que son los ya vistos métodos especiales.

Veamos el siguiente ejemplo donde podemos llamar a una función especial desde un objeto en en cual no se ha definido dicha función:

import os

os.system("cls")

class Vehiculo:
        color = "Blanco"
        marca = "Volkswagen"
        modelo = "Beetle"
        carroceria = "Coupe"
        numero = "53"

        def acelerar(self):
                print("ruuuun ruuuun")
Herbie = Vehiculo()

print("Propiedad modelo impreso a través del objeto Herbie")
print(Herbie.modelo)
print('Propiedad modelo impreso a través del método __repr__()')
print(Herbie.modelo.__repr__())
print('Propiedad modelo impreso a través de la función incorporada en Python repr()')
print(repr(Herbie.modelo))

Resultado:

Propiedad modelo impreso a través del objeto Herbie

Beetle

Propiedad modelo impreso a través del método __repr__()

'Beetle'

Propiedad modelo impreso a través de la función incorporada en Python repr()

'Beetle'

Como podemos comprobar hemos accedido a una función en el objeto Herbie que no habíamos definido previamente en su clase vehiculo, el método especial __repr__(). Dicho método está definido previamente  por Python (lo que lo hace un método especial) miembro de la superclase Object y por lo tanto todas las clases y objetos creados en Python heredan dicho método. Aunque no es el objetivo de este apartado explicar la funcionalidad de método especial __repr__, de momento basta con decir que es una función definida dentro de la superclase Object de Python que permite representar cualquier dato como una cadena de caracteres o string. Es importante destacar que la función __repr__() no convierte un tipo de dato en otro, solamente muestra o 'representa' el dato obtenido como una cadena.


Comentarios

Entradas populares