Clases y objetos en Python II parte 2
Encapsulamiento de Métodos.
Así como se pueden encapsular las propiedades de una clase para que solo sean accesibles desde dentro de ella, también es posible encapsular los métodos, con el mismo propósito, o sea para que solamente sean accesibles desde dentro de la clase. Para lograr esto, al igual que con las propiedades, basta con anteponer en el nombre del método dos guiones bajos seguidos (__). Para ejemplificar lo anterior supongamos que tenemos una clase vehiculo con un constructor que inicializa algunos valores básicos encapsulados tales como marca, modelo, cantidad de puertas y carrocería, mientras que otras propiedades no están encapsuladas, tales como color, presión de aceite de motor, estado y nivel de combustible. Veamos el código en la práctica:
import os
os.system('cls')
class automovil():
def __init__(self) -> None:
self.__marca = 'Ford'
self.__modelo = 'Mondeo'
self.color = 'Blanco'
self.__puertas = 4
self.__carroceria = 'Sedán'
self.__presion_aceite_min = 30
self.__presion_aceite_max = 45
self.presion_aceite = int((self.__presion_aceite_max-self.__presion_aceite_min)/2)+self.__presion_aceite_min
self.__estado = 'Detenido'
self.__capacidad_combustible = 70
self.nivel_combustible = self.__capacidad_combustible
def __status(self):
if self.__presion_aceite_min < self.presion_aceite and self.presion_aceite < self.__presion_aceite_max and self.nivel_combustible > 1:
return 'Ok'
def info(self):
print(f'''
************** Información actual del vehículo ***********************
*** Marca: {self.__marca}
*** Modelo: {self.__modelo}
*** Color: {self.color}
*** Puertas: {self.__puertas}
*** Carrocería: {self.__carroceria}
*** Presión de aceite: {self.presion_aceite} PSI
*** Estado actual: {self.__estado}
*** Nivel combustible: {self.nivel_combustible} litros
********************** Fin de datos **********************************
''')
def arrancar(self,llave):
if llave:
if self.__status() == 'Ok' and self.__estado=='Detenido':
print('Encendiendo vehículo, todo OK')
self.__estado = 'Rodando'
else:
print('Se ha encontrado un problema. No se puede arrancar el auto')
else:
if self.__estado=='Rodando':
print('Apagando vehículo...')
self.__estado='Detenido'
else:
print('Vehiculo ya se encuentra apagado. Contacte a servicio técnico.')
auto1=automovil()
auto1.info()
print('Evento: Se inician las pruebas y se pasa el switch a la posición encendido')
auto1.arrancar(True)
auto1.info()
print('Evento: se consumen 10 litros de combustible y sube la presión de aceite en 3 PSI')
auto1.nivel_combustible -= 10
auto1.presion_aceite +=3
auto1.info()
print('Evento: se pasa el switch a la posición apagado')
auto1.arrancar(False)
auto1.info()
print('Evento: sube la presión de aceite en 8 PSI')
auto1.presion_aceite +=8
auto1.info()
print(f'''
Evento: se pasa el switch a la posición encendido,
dismunuye la presión de aceite en 7 PSI y se consumen 40 litros de combustible''')
auto1.arrancar(True)
auto1.nivel_combustible -= 40
auto1.presion_aceite -=7
auto1.info()
print('Evento: se pasa el switch a la posición encendido 2 veces seguidas')
auto1.arrancar(True)
auto1.arrancar(True)
auto1.info()
print('Evento: Ingreso al taller para pintar de color rojo el vehículo, apagando el vehículo')
auto1.arrancar(False)
auto1.color = 'Rojo'
auto1.info()
print('Evento: Se vacía por completo el tanque de combustible del vehículo')
auto1.nivel_combustible=0
auto1.info()
print('Evento: se pasa el switch a la posición encendido')
auto1.arrancar(True)
print('Evento: Se agregan 5 litros de combustible para poder sacar el vehículo del taller de pintura')
auto1.nivel_combustible += 5
auto1.info()
print('Evento: se pasa el switch a la posición encendido')
auto1.arrancar(True)
auto1.info()
print('Evento: se pasa el switch a la posición apagado y se finalizan las pruebas')
auto1.info()
Resultado de las pruebas:
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 37 PSI
*** Estado actual: Detenido
*** Nivel combustible: 70 litros
********************** Fin de datos **********************************
Evento: Se inician las pruebas y se pasa el switch a la posición encendido
Encendiendo vehículo, todo OK
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 37 PSI
*** Estado actual: Rodando
*** Nivel combustible: 70 litros
********************** Fin de datos **********************************
Evento: se consumen 10 litros de combustible y sube la presión de aceite en 3 PSI
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 40 PSI
*** Estado actual: Rodando
*** Nivel combustible: 60 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición apagado
Apagando vehículo...
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 40 PSI
*** Estado actual: Detenido
*** Nivel combustible: 60 litros
********************** Fin de datos **********************************
Evento: sube la presión de aceite en 8 PSI
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 48 PSI
*** Estado actual: Detenido
*** Nivel combustible: 60 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición encendido,
dismunuye la presión de aceite en 7 PSI y se consumen 40 litros de combustible
Se ha encontrado un problema. No se puede arrancar el auto
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Detenido
*** Nivel combustible: 20 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición encendido 2 veces seguidas
Encendiendo vehículo, todo OK
Se ha encontrado un problema. No se puede arrancar el auto
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Blanco
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Rodando
*** Nivel combustible: 20 litros
********************** Fin de datos **********************************
Evento: Ingreso al taller para pintar de color rojo el vehículo, apagando el vehículo
Apagando vehículo...
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Rojo
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Detenido
*** Nivel combustible: 20 litros
********************** Fin de datos **********************************
Evento: Se vacía por completo el tanque de combustible del vehículo
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Rojo
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Detenido
*** Nivel combustible: 0 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición encendido
Se ha encontrado un problema. No se puede arrancar el auto
Evento: Se agregan 5 litros de combustible para poder sacar el vehículo del taller de pintura
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Rojo
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Detenido
*** Nivel combustible: 5 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición encendido
Encendiendo vehículo, todo OK
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Rojo
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Rodando
*** Nivel combustible: 5 litros
********************** Fin de datos **********************************
Evento: se pasa el switch a la posición apagado y se finalizan las pruebas
************** Información actual del vehículo ***********************
*** Marca: Ford
*** Modelo: Mondeo
*** Color: Rojo
*** Puertas: 4
*** Carrocería: Sedán
*** Presión de aceite: 41 PSI
*** Estado actual: Rodando
*** Nivel combustible: 5 litros
********************** Fin de datos **********************************
Como podemos comprobar a lo largo de la serie de eventos que ocurren desde la salida de la fabrica del vehículo hasta su retorno luego de la aplicación de la nueva pintura se han accedido a propiedades y métodos encapsulados y no encapsulados de la clase vehículo.
Método NEW.
Este método especial es el que mejor encaja en la clasificación de 'constructor', ya que es el método que efectivamente crea un nuevo objeto de su clase y lo devuelve. Se ejecuta automáticamente al instanciar una clase en un objeto con lo cual no es necesaria su invocación, con lo cual ya serían dos métodos especiales constructores que se ejecutan de manera automática al crear un objeto. En este punto es importante aclarar que primero se ejecuta el método NEW y posteriormente el método INIT. Para no olvidar este orden, a pesar de ser bastante intuitivo, lo podemos comparar con la vida real, en donde primero se crea físicamente un objeto, siguiendo el ejemplo del vehículo primero se crea el vehículo físicamente y luego se le asignan las propiedades como color, número, marca, modelo, etc.
Es importante destacar en este punto que, a diferencia del método especial INIT, el método NEW no pertenece a una clase en particular, lo cual lo convierte en un método especial estático, ya que no puede accesar y modificar el estado de un objeto como lo hace el método INIT, a pesar que lo haga solamente una vez durante toda la vida de objeto.
Como pudimos ver en la explicación de método INIT, el método NEW se ejecuta sin necesidad de llamarlo específicamente, sin embargo existe la posibilidad de crear un objeto manualmente usando el super objeto OBJECT, sin embargo Python no ejecutará automáticamente el método INIT de su clase instanciada. Para ver el siguiente ejemplo nos vamos a valer del atributo especial DICT del objeto creado para comprobar su contenido.
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)
Auto2 = object.__new__(Vehiculo,'General Lee','Naranja','Dodge','Charger',\
'Fast Back','01')
print(f'Contenido del objeto Auto2 sin inicialización manual: {Auto2.__dict__}')
Vehiculo.__init__(Auto2,'General Lee','Naranja','Dodge','Charger','Fast Back','01')
print(f'Contenido del objeto Auto2 luego de a inicialización manual:\
{Auto2.__dict__}')
Resultado:
Objeto inicializado con todas sus propiedades
Herbie Blanco Wolkswagen Beetle Coupe 53
Contenido del objeto Auto2 sin inicialización manual: {}
Objeto inicializado con todas sus propiedades
Contenido del objeto Auto2 luego de a inicialización manual: {'nombre': 'General Lee', 'color': 'Naranja', 'marca': 'Dodge', 'modelo': 'Charger', 'carroceria': 'Fast Back', 'numero': '01'}
Como podemos comprobar al ejecutar un PRINT sobre la propiedad DICT del objeto creado manualmente sin una previa inicialización manual, el resultado es un diccionario vacío. Sin embargo luego de inicializar dicho objeto invocando manualmente a su método INIT, podemos ver que ahora al al ejecutar un PRINT sobre su atributo DICT aparecen sus propiedades debidamente inicializadas.
En conclusión es importante recordar que siempre que se creen objetos manualmente a través del supero object, éstos tambien deben ser inicializados manualmente invocando e constructor INIT del objeto creado. Caso contrario el objeto va a existir pero totalmente vacío como vimos en el ejemplo.
En el siguiente ejemplo vamos a utilizar objetos para crear objetos de la clase Vehiculos en donde los objetos instanciados permiten definir propiedades del vehículo como marca, modelo, color, capacidad del tanque de combustible rendimiento de combustible por cada 100 km. de recorrido. Adicionalmente la clase vehículo tiene un método que permite calcular la cantidad de veces necesarias de repostar por combustible y la cantidad total de combustible consumido en un viaje solamente pasando como argumento la distancia en Km. del viaje a realizar.
import os
os.system("cls")
class Vehiculo:
def __init__(self,nombre,color,marca,modelo,capacidad_combustible,rendimiento_combustible):
self.nombre=nombre
self.color=color
self.marca=marca
self.modelo=modelo
self.capacidad_combustible=capacidad_combustible #capacidad del tanque en litros
self.rendimiento_combustible=rendimiento_combustible #consumo de combustible en litros por cada 100 km.
def Viajar(self,distancia):
nLitrosConsumo=distancia*(self.rendimiento_combustible/100)
nCantidadRepostas=nLitrosConsumo/self.capacidad_combustible
print(f'{self.nombre} va a consumir {round(nLitrosConsumo,2)} l. de combustible para recorrer {distancia} Km.')
print(f'{self.nombre} necesitará {round(nCantidadRepostas)} repostas para recorrer {distancia} Km.')
print(f'El costo total en combustible en {self.nombre} a precio de ANCAP es de: {round(nLitrosConsumo*fPrecioCombustibleAncap,2)} $U')
print(f'El costo total en combustible al precio máximo estipulado en Uruguay es de: {round(nLitrosConsumo*fPrecioCombustibleOtros,2)} $U\n')
Auto1=Vehiculo('Herbie','Blanco','Volkswagen','Beetle',55,7)
Auto2=Vehiculo('General Lee','Naranja','Dodge','Charger R/T',72,4.5)
fPrecioCombustibleAncap= 68.04
fPrecioCombustibleOtros= 77.88
Auto1.Viajar(4270)
Auto2.Viajar(4270)
Resultado:
Herbie va a consumir 298.9 l. de combustible para recorrer 4270 Km.
Herbie necesitará 5 repostas para recorrer 4270 Km.
Herbie va a consumir 298.9 l. de combustible para recorrer 4270 Km.
Herbie necesitará 5 repostas para recorrer 4270 Km.
El costo total en combustible en Herbie a precio de ANCAP es de: 20337.16 $U
El costo total en combustible al precio máximo estipulado en Uruguay es de: 23278.33 $U
General Lee va a consumir 192.15 l. de combustible para recorrer 4270 Km.
General Lee necesitará 3 repostas para recorrer 4270 Km.
El costo total en combustible en General Lee a precio de ANCAP es de: 13073.89 $U
El costo total en combustible al precio máximo estipulado en Uruguay es de: 14964.64 $U
Se le ha incluido el dato de los costos del combustible a precio oficial en Uruguay a la fecha de esta publicación para el cálculo del gasto en nafta. Como nota adicional podemos observar que se ha usado la función incorporada ROUND, a fin de mostrar en el resultado un número redondeado hacia arriba con solo dos decimales.
En conclusión se ha realizado un simple programa en Python que hace uso de la POO para crear objetos a partir de una clase llamada vehiculo y hacer un cálculo básico invocando las propiedades y métodos de dicha clase.
A pesar de estar ya creados y funcionando los objetos, es posible modificar sus datos accediendo a sus propiedades a través del operador punto (.). Ejemplo:
import os
os.system("cls")
class Vehiculo:
def __init__(self,nombre,color,marca,modelo) -> None:
self.nombre=nombre
self.color=color
self.marca=marca
self.modelo=modelo
def Imprimir(self):
datos=f'''
Datos del Vehículo:
Nombre: {self.nombre}
Color: {self.color}
Marca: {self.marca}
Modelo: {self.modelo}
'''
print(datos)
Auto1 = Vehiculo('Herbie','Blanco','Volkswagen','Beetle')
Auto1.Imprimir()
Auto1.nombre = input('Nuevo nombre: ')
Auto1.color = input('Nuevo color: ')
Auto1.marca = input('Nueva marca: ')
Auto1.modelo = input('Nuevo modelo: ')
Auto1.Imprimir()
Resultado:
Datos del Vehículo:
Nombre: Herbie
Color: Blanco
Marca: Volkswagen
Modelo: Beetle
Nuevo nombre: Mi auto
Nuevo color: Verde
Nueva marca: Toyota
Nuevo modelo: Corolla
Datos del Vehículo:
Nombre: Mi auto
Color: Verde
Marca: Toyota
Modelo: Corolla
Como podemos ver hemos modificado los datos miembros de la clase vehiculo de objeto Auto1. Al ejecutar por segunda vez el método Imprimir() muestra los nuevos valores del objeto recién cargados por el usuario. Nótese como dato adicional como se ha hecho uso del formateo de cadena de caracteres a través de a instrucción F.STRINGS también conocida como literales de cadenas formateadas. Básicamente se le asigna a una variable una cadena encerrada entre comillas triples anteponiendo la letra F. Este formateo de cadenas de caracteres reconoce incluso saltos de línea, haciendo mas sencillo el mejoramiento de la legibilidad de los datos mostrados por pantalla.
Comentarios
Publicar un comentario