Clase 30. Python 6
Clase 30. Python 6
Clase 30
PYTHON 6
Colaboración entre clases y
encapsulamiento
Les damos la bienvenida
Vamos a comenzar a grabar la clase
Clase 29 Clase 30 Clase 31
Enunciado 1:
monto 3 objetos
de la clase
nombre Cliente
Atributos Atributos
__init__
Cliente Banco __init__
depositar
Métodos Métodos operar
extraer
depositos_t
retornar_mo otales
nto
Colaboración de clases | Clase Cliente
Clase Cliente
En el método __init__ se inicializan
class Cliente:
los atributos nombre con el valor del def __init__(self,nombre):
self.nombre=nombre
parámetro, y monto con el valor cero. self.monto=0
def operar(self):
self.cliente1.depositar(100)
self.cliente2.depositar(150)
self.cliente3.depositar(200)
self.cliente3.extraer(150)
def depositos_totales(self):
total=self.cliente1.retornar_monto()+self.cliente2.retornar_monto()+self.cliente3.retornar_monto()
print("El total de dinero en el banco es: {}".format(total))
self.cliente1.imprimir()
self.cliente2.imprimir()
self.cliente3.imprimir()
Colaboración de clases | Programa principal
En el programa principal se instancia un objeto de la clase Banco, y se invocan
sus métodos operar() y depositos_totales():
Programa principal Terminal
# Programa principal: El total de dinero en el banco es: 300
banco1 = Banco() Juan tiene depositada la suma de 100
banco1.operar() Ana tiene depositada la suma de 150
banco1.depositos_totales() Diego tiene depositada la suma de 50
Enunciado 2:
suspendidos codigo
(lista)
nombre
Atributos
Atributos __init__
Cliente
de clase
imprimir
Métodos
suspender
esta_suspendida
Atributos de clase | Clase Cliente
Clase Cliente (Parte I)
La lista suspendidos es compartida
class Cliente:
por todos los objetos de la clase. suspendidos=[] #Atributo de Clase
def __init__(self,codigo,nombre):
El método imprimir muestra los self.codigo=codigo #Atributo de instancia
datos y estado de la cuenta de cada self.nombre=nombre #Atributo de instancia
correspondiente: cliente3.suspender()
cliente4.suspender()
Atributos de clase | Ejecución
Si en este punto invocamos el método imprimir de cada instancia, vemos:
Programa principal Terminal Es importante recordar que todos los
# Programa principal: Codigo: 1 objetos acceden a una única lista
cliente1 = Cliente(1,"Juan") Nombre: Juan
cliente2 = Cliente(2,"Ana") No esta suspendido llamada suspendidos gracias a que se
cliente3 = Cliente(3,"Diego") ____________________ definió como un atributo de clase.
cliente4 = Cliente(4,"Pedro") Codigo: 2
Nombre: Ana
No esta suspendido Podemos ver el contenido de la lista
cliente3.suspender()
____________________ con:
cliente4.suspender() Codigo: 3
Nombre: Diego Programa principal Terminal
cliente1.imprimir() Esta suspendido
cliente2.imprimir() print(Cliente.suspendidos) [3, 4]
____________________
cliente3.imprimir() Codigo: 4
cliente4.imprimir() Nombre: Pedro
Esta suspendido
____________________
Composición
Cada clase que definimos es un nuevo tipo de datos, con sus atributos y
métodos. Y al igual que los demás tipos de datos, los objetos instanciados a
partir de ellas se pueden utilizar como parte de colecciones o incluso ser parte
de otras clases.
La composición es uno de los conceptos fundamentales de la POO. Tiene
lugar cuando una clase (clase “que tiene”) hace referencia a uno o más objetos
de otras clases (clases “que son parte de”), como una variable de instancia.
+info
Al usar el nombre de la clase o al crear el objeto, se accede a los miembros de
una clase dentro de otra clase. La composición permite crear tipos complejos
mediante la combinación de objetos de diferentes clases.
Composición
Mediante la composición solo se puede utilizar la otra clase (la “que es parte
de”), no se puede modificar ni extender la funcionalidad de la misma. No
proporciona funciones adicionales. Así, cuando se necesita usar otra clase sin
ninguna modificación, se recomienda la composición
Enunciado 3:
● Define una clase Pelicula que gestione datos de películas
● La clase Película tiene los atributos título, duración y lanzamiento, e
implementa __str__ para mostrar sus datos.
● Define la clase Catalogo, que administra una lista de películas. Estas
películas son objetos de la clase Película. Debe implementar los métodos
mostrar y agregar películas.
Composición
Se implementan dos clases, que llamaremos Pelicula (“es parte de”) y
Catalogo (clase “que tiene”) respectivamente
lanzamiento
Atributos
Catalogo Peliculas
de clase __init__
__init__
Métodos agregar Métodos
__str__
mostrar
Composición | Clase Pelicula
Definición de la clase Pelicula. Esta es la clase que, en la composición, se
comporta como “clase que es parte de”, ya que sus instancias serán parte de
la clase Catalogo.
Clase Pelicula
class Pelicula:
# Constructor de clase
def __init__(self, titulo, duracion, lanzamiento):
self.titulo = titulo
self.duracion = duracion
self.lanzamiento = lanzamiento
print(f'Se ha creado la película: {self.titulo}')
def __str__(self):
return f'{self.titulo} ({self.lanzamiento})'
Composición | Clase Catalogo
Definición de la clase Catalogo. En la composición se comporta como “clase
que tiene”, ya uno de sus atributos de instancia es un objeto de la clase
Pelicula.
Clase Catalogo
class Catalogo:
peliculas = [] # Esta de objetos de la clase Pelicula
# Constructor de clase
def __init__(self, peliculas=[]):
Catalogo.peliculas = peliculas
def mostrar(self):
for p in Catalogo.peliculas:
print(p) # Print toma por defecto str(p)
Composición | Programa principal
Definición de la clase Catalogo. En la composición se comporta como “clase
que tiene”, ya uno de sus atributos de instancia es un objeto de la clase
Pelicula.
Programa principal Terminal
# Instanciamos una película
peli1 = Pelicula("El Padrino", 175, 1972)
Se ha creado la película: El Padrino
# Instanciamos un catálogo que contiene una pelicula
c = Catalogo([peli1]) El Padrino (1972)
c.mostrar()
Se ha creado la película: El Padrino: Parte 2
# Añadimos una nueva película al catálogo:
El Padrino (1972)
c.agregar(Pelicula("El Padrino: Parte 2", 202, 1974)) El Padrino: Parte 2 (1974)
c.mostrar()
Encapsulación | Atributos protegidos
Si el nombre de un atributo está precedido por un guión bajo, significa que es
un atributo protegido. Solo puede ser accedido por esa clase y es una buena
práctica para los atributos (o métodos) de uso interno, sobre todo en
programas que recurren a muchas clases. De lo contrario, resulta, en realidad,
innecesario.
Programa principal Terminal
class Vehiculo: Traceback (most recent call last):
def __init__(self, marca, color, placa): File "prueba.py", line 13, in <module>
self._marca = marca print(coche.marca)
self._color = color AttributeError: 'Vehiculo' object has no attribute
self._placa = placa
'marca'. Did you mean: '_marca'?
coche = Vehiculo("Ford", "Rojo", "AB123CD")
print(coche.marca)
Encapsulación
Encapsulación se refiere al ocultamiento de los atributos o métodos de una
clase al exterior, para que no se puedan acceder ni modificar desde fuera. Por
defecto Python no oculta los atributos y métodos de una clase al exterior:
Programa principal Terminal
class Clase:
atributo_clase = "Hola"
def __init__(self, atributo_instancia):
self.atributo_instancia = atributo_instancia
Para ocultar métodos y atributos del exterior se usa doble guión bajo __ en el
comienzo de su nombre. Esto hará que Python los interprete como “privados”.
Encapsulación | Decoradores - setters
Getters y setters:
Un setter permite crear métodos que
class Bebidas:
permiten modificar el valor de un def __init__(self):
atributo privado. self.__bebida = 'Naranja'
@property
En Python se declaran escribiendo def favorita(self):
return f"La bebida preferida es:
antes del método un decorador con {self.__bebida}"
su nombre seguido de .setter.
@favorita.setter
def favorita(self, bebida):
Junto con el decorador @property self.__bebida = bebida
mi_clase = Clase()
#mi_clase.__atributo_clase #AttributeError (atributo no accesible)
#mi_clase.__mi_metodo() #AttributeError (método no accesible)
print(mi_clase.atributo_clase) Hola
mi_clase.metodo_normal() Que tal
Encapsulación
En el ejemplo se ve como los atributos y métodos de la clase Clase cuyos
nombres comienzan con __ no son “visibles” desde el exterior de la clase.
En efecto, __atributo_clase y __mi_metodo() están “encapsulados” en la Clase.
Se puede acceder y modificar desde su interior, pero cuando intentamos
hacerlo desde el exterior Python arroja un error explicando que no es posible.
Por ejemplo, en el código anterior al intentar usar __atributo_clase:
Terminal
Traceback (most recent call last):
File "prueba.py", line 13, in <module>
mi_clase.__atributo_clase
AttributeError: 'Clase' object has no attribute '__atributo_clase' Did you mean:
'atributo_clase'?
Encapsulación
Entonces, los atributos de una clase pueden presentar tres niveles de
privacidad:
@property
def favorita(self):
return f"La bebida preferida es:
{self.__bebida}"
La bebida
obj1 = Bebidas() preferida es:
print(obj1.favorita) Naranja
Colaboración y encapsulación
Para finalizar, vamos a analizar un nuevo ejemplo:
Enunciado 4:
● Crear una clase Carrera, que tenga un método constructor y otro que
permita agregar materias a la carrera.
● Crear otra clase, Materia, que tenga los atributos privados nombre,
profesor y fecha_inicio. Proporcionar un método para acceder a la
fecha_inicio.
Del enunciado se deduce que necesitamos objetos de dos clases: Carrera y
Materia. Para cada una de estas entidades necesitamos crear una clase, con
sus atributos y métodos.
Colaboración y encapsulación
Identificadas las clases, que llamaremos Cliente y Banco respectivamente,
definimos qué atributos y métodos necesitamos implementar en cada una.
nombre
nombre
Atributos profesor
Atributos materias
(es un conjunto fecha_inicio
de tuplas) Materia
Carrera __init__
__init__
fecha_inicio
Métodos Métodos
(getter)
agregar_materia
fecha_inicio
(setter)
Colaboración y encapsulación
Clase Materia Clase Carrera
class Materia: class Carrera:
def __init__(self, nombre, profesor, fecha): def __init__(self, nombre):
self.nombre = nombre self.nombre = nombre
self.profesor = profesor
#Fecha no puede ser anterior a 2006 #Contendrá tuplas (código, materia)
self.fecha_inicio = fecha self.materias = {}
@fecha_inicio.setter
def fecha_inicio(self, fecha):
# print("Estoy seteando la fecha de inicio")
if fecha < 2006:
self._fecha_inicio = 2006
else:
self._fecha_inicio = fecha
Colaboración y encapsulación
Clase Materia Terminal
#Creamos una carrera y tres materias
carrera1 = Carrera("Ingeniería en Sistemas")
algebra = Materia("Algebra", "Juan Quinteros", 2004)
fisica = Materia("Física", "Pedro Perez", 2012)
programacion = Materia("Programación", "Lorena Ríos",2022)
Videos: