Clases y objetos en Python II parte 1

Constructores.

Un constructor en Python es método especial que es llamado por el programa al momento de instanciar un objeto usando las definiciones de su clase y su función es la de inicializar su estado, lo que se traduce en asignar valores a los datos miembros de la clase cuando se cree un objeto instanciado a partir de dicha clase. En otras palabras un constructor hace que por el simple hecho de crear un objeto a partir de una clase, éste ya tenga ciertas características o propiedades.

Un constructor también contiene un conjunto de instrucciones que serán ejecutadas cuando se cree un objeto. Este código se ejecuta tan pronto un objeto de una clase sea instanciado. Es importante destacar que un constructor también verifica que hayan suficientes recursos disponibles para que el objeto realice otra tarea para iniciarse.

Método INIT.


En Python uno de los métodos constructores de objetos es el método especial __init__, que a pesar de estar clasificado como 'constructor' en realidad inicializa un objeto como ya veremos mas adelante. Para declararlo se debe usar la palabra reservada DEF seguido de la palabra reservada INIT entre guiones bajos dobles "__" dentro de la definición de la clase de la siguiente manera:

def __init__

El método INIT es ejecutado cada vez que se crea un objeto de una clase y su única función es inicializar los datos miembros de objeto instanciado. Es importante recordar que solamente se usa dentro de las clases. También es necesario usar la palabra reservada SELF entre paréntesis () luego del segundo doble guión bajo de INIT para hacer referencia a las propiedades del objeto inicializado correctamente, de tal forma que las propiedades del objeto instanciado se puedan declarar usando la palabra reservada SELF. y a continuación la propiedad que se le desea asignar al objeto. De no usarse la palabra reservada SELF, Python va a interpretar que se esta refiriendo a una variable utilizada dentro del método pero no a una propiedad de la clase.

Veamos el siguiente ejemplo ya con el uso mas apropiado de las propiedades de los objetos en Python:

import os
os.system("cls")

class Vehiculo:
        def __init__(self,nombre,color,marca,modelo,carroceria,numero):
                self.nombre = nombre
                self.color = color
                self.marca = marca
                self.modelo = modelo
                self.carroceria = carroceria
                self.numero = numero
                print('Objeto inicializado con todas sus propiedades')
        def acelerar(self):
                print("ruuuun ruuuun")      
       
Auto1 = Vehiculo('Herbie','Blanco','Wolkswagen','Beetle','Coupe','53')
print(Auto1.nombre,Auto1.color,Auto1.marca,Auto1.modelo,Auto1.carroceria,Auto1.numero)

Resultado:

Objeto inicializado con todas sus propiedades
Herbie Blanco Wolkswagen Beetle Coupe 53

Como se puede observar, se implementó una instrucción PRINT con un mensaje dentro de la declaración del método especial INIT de la clase Vehiculo, haciendo que cada vez que se cree una instancia de dicha clase se ejecute la instrucción mostrando el mensaje "Objeto inicializado con todas sus propiedades" por pantalla, sin necesidad de hacer el llamado explícitamente. También se habrán inicializado sus propiedades de manera automática al instanciar la clase en el objeto Herbie, como lo anuncia el mensaje implementado.

También es posible definir de manera predeterminada las propiedades de la clase dentro del constructor __INIT__:

class automovil():
        def __init__(self):
                self.color='Rojo'
                self.puertas='5'
                self.marca ='Ford'
                self.modelo='Focus'
                self.peso=1384
                self.largo=4.38
                self.ancho=1.82
                self.estado=False

        def arrancar(self,modo):
                if modo:
                        self.estado=True
                        return 'Rodando'
                else:
                        self.estado=False
                        return 'Detenido'
        def info(self):
                print('* * * * * Información del vehículo * * *')
                print('Marca: ',self.marca)
                print('Modelo: ',self.modelo)
                print('Puertas: ',self.puertas)
                print('Color: ',self.color)
                print('Peso: ',self.largo)
                print('Largo: ', self.largo)
                print('Ancho: ', self.ancho)
                if self.estado:
                        print('Estado: Rodando')
                else:
                        print('Estado: Detenido')
               

auto1=automovil()

auto2=automovil()

print('El auto1 esta ahora: ',auto1.arrancar(False))
print('El auto2 esta ahora: ', auto2.arrancar(True))

auto1.info()
auto2.info()

A pesar de haberse definido las propiedades del objeto vehiculo() dentro del método especial constructor ::INIT::, es posible modificar sus valores desde fuera de la clase. Veamos el siguiente ejemplo:

class automovil():
        def __init__(self) -> None:
                self.marca = 'Chevrolet'
                self.modelo = 'Joy'
                self.ruedas = 4
                self.color = 'Rojo'
                self.ancho = 170
                self.largo = 393
        def info(self):
                print('* * * INFORMACION TECNICA DEL VEHICULO * * *')
                print('Marca: ',self.marca)
                print('Modelo: ', self.modelo)
                print('Número de ruedas: ',self.ruedas)
                print('Color: ', self.color)
                print('Ancho: ',self.ancho)
                print('Largo: ', self.largo)


auto1=automovil()
auto1.info()
auto1.ruedas=2
auto1.info()

Resultado:

* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  4
Color:  Rojo
Ancho:  170
Largo:  393
* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  2
Color:  Rojo
Ancho:  170
Largo:  393

Como podemos comprobar se ha creado una clase llamada vehículo la cual ha sido instanciada en un objeto llamado auto1. En dicha clase se han definido algunas propiedades predeterminadas en su constructor a través del método especial __INIT__, dentro de las cuales se encuentra el número de ruedas que posee. or defecto se ha establecido que tiene 4. Igualmente la clase posee un método que imprime los valores de los atributos por pantalla.

En la ejecución del cuerpo del programa podemos ver que la clase instanciada en el objeto auto1 llama a su método info() para mostrar los valores de las propiedades, comprobando que todos están como se definieron en el constructor, luego a través de una instrucción que llama a la propiedad ruedas, se modifica el valor de 4 a 2, quedando así un automóvil con 2 ruedas, que como sabemos no es posible. Pudiendose comprobar que esta propiedad fue efectivamente modificada al ejecutar nuevamente el método info().

Para evitar la modificación voluntaria o involuntaria de una propiedad definida en una clase ya sea dentro o fuera del constructor, basta con anteponer dos guiones bajos seguidos antes del nombre de la propiedad, esto hace que la propiedad sea solo accesible desde el interior de la clase. A esta propiedad de la programación orientada a objetos se le conoce como encapsulamiento. Veamos como quedaría el código encapsulando la propiedad ruedas de la clase automovil():

class automovil():
        def __init__(self) -> None:
                self.marca = 'Chevrolet'
                self.modelo = 'Joy'
                self.__ruedas = 4
                self.color = 'Rojo'
                self.ancho = 170
                self.largo = 393
        def info(self):
                print('* * * INFORMACION TECNICA DEL VEHICULO * * *')
                print('Marca: ',self.marca)
                print('Modelo: ', self.modelo)
                print('Número de ruedas: ',self.__ruedas)
                print('Color: ', self.color)
                print('Ancho: ',self.ancho)
                print('Largo: ', self.largo)


auto1=automovil()
auto1.info()
auto1.__ruedas=2
auto1.info()

Resultado:

* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  4
Color:  Rojo
Ancho:  170
Largo:  393
* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  4
Color:  Rojo
Ancho:  170
Largo:  393

Como podemos comprobar a pesar de haber cambiado explicitamente el valor de la propiedad número de ruedas, éste se mantiene tal cual como fue definido en su constructor debido a que es una propiedad que está encapsulada gracias al uso de doble guión bajo (__) antes del nombre. Sin embargo si deseamos que esta propiedad encapsulada sea modificada es necesario que se haga desde dentro de la clase. Veamos como quedaría esta opción:

class automovil():
        def __init__(self) -> None:
                self.marca = 'Chevrolet'
                self.modelo = 'Joy'
                self.__ruedas = 4
                self.color = 'Rojo'
                self.ancho = 170
                self.largo = 393
        def info(self):
                print('* * * INFORMACION TECNICA DEL VEHICULO * * *')
                print('Marca: ',self.marca)
                print('Modelo: ', self.modelo)
                print('Número de ruedas: ',self.__ruedas)
                print('Color: ', self.color)
                print('Ancho: ',self.ancho)
                print('Largo: ', self.largo)
        def modifica_ruedas(self,ruedas):
                self.__ruedas=ruedas


auto1=automovil()
auto1.info()
auto1.__ruedas=2
auto1.info()
auto1.modifica_ruedas(3)
auto1.info()

Resultado:

* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  4
Color:  Rojo
Ancho:  170
Largo:  393
* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  4
Color:  Rojo
Ancho:  170
Largo:  393
* * * INFORMACION TECNICA DEL VEHICULO * * *
Marca:  Chevrolet
Modelo:  Joy
Número de ruedas:  3
Color:  Rojo
Ancho:  170
Largo:  393

Como podemos comprobar se ha podido cambiar el valor de una propiedad encapsulada de la clase vehiculo() para lo cual ha sido necesario recurrir a un método que lo realizara desde dentro de la clase, ya que como hemos visto anteriormente no es posible modificar los valores encapsulados de una clase desde fuera de dicha clase.



Comentarios

Entradas populares