Herencia y Polimorfismo en Programación Orientada a Objetos
Resumen
El concepto de herencia en programación permite que una clase derive atributos y métodos de otra, facilitando la reutilización de código y la creación de estructuras jerárquicas lógicas. En este ejercicio, se aplica herencia para modelar una concesionaria que vende autos, bicicletas y camiones.
¿Cómo se crea la clase base para los vehículos?
Primero, se define una clase base llamada Vehículo, que contiene atributos comunes como marca, modelo, precio y disponibilidad. Los métodos básicos incluyen verificar disponibilidad, obtener el precio y vender el vehículo.
classVehículo:def__init__(self, marca, modelo, precio): self.marca = marca
self.modelo = modelo
self.precio = precio
self.disponible =Truedefvender(self):if self.disponible: self.disponible =Falseprint(f"El vehículo {self.marca} ha sido vendido.")else:print(f"El vehículo {self.marca} no está disponible.")defestado(self):return self.disponible
defget_price(self):return self.precio
¿Cómo se implementa la herencia en las clases derivadas?
Las clases Auto, Bicicleta y Camión heredan de Vehículo. Cada una puede personalizar métodos específicos según sus necesidades.
classAuto(Vehículo):defstart(self):if self.disponible:returnf"El motor del coche {self.marca} está en marcha."else:returnf"El coche {self.marca} no está disponible."defstop(self):if self.disponible:returnf"El motor del coche {self.marca} se ha detenido."else:returnf"El coche {self.marca} no está disponible."
¿Cómo se manejan las instancias de las clases en la concesionaria?
Se crean instancias de Auto, Cliente y Concesionaria para manejar el inventario y las ventas.
classCliente:def__init__(self, nombre): self.nombre = nombre
self.autos =[]defcomprar_auto(self, auto):if auto.estado(): self.autos.append(auto) auto.vender()else:print(f"El auto {auto.marca} no está disponible.")classConcesionaria:def__init__(self): self.inventario =[] self.clientes =[]def añadir_auto(self, auto): self.inventario.append(auto)defregistrar_cliente(self, cliente): self.clientes.append(cliente)defmostrar_disponibles(self):for auto in self.inventario:if auto.estado():print(f"{auto.marca}{auto.modelo} está disponible por {auto.get_price()}.")
¿Cómo se aplican las operaciones en la concesionaria?
Finalmente, se crean instancias y se realizan operaciones para mostrar la funcionalidad del sistema.
# Crear autosauto1 = Auto("Toyota","Corolla",20000)auto2 = Auto("Honda","Civic",22000)auto3 = Auto("Ford","Mustang",30000)# Crear clientecliente = Cliente("Carlos")# Crear concesionariaconcesionaria = Concesionaria()concesionaria.añadir_auto(auto1)concesionaria.añadir_auto(auto2)concesionaria.añadir_auto(auto3)concesionaria.registrar_cliente(cliente)# Mostrar autos disponiblesconcesionaria.mostrar_disponibles()# Comprar autocliente.comprar_auto(auto1)# Mostrar autos disponibles después de la compraconcesionaria.mostrar_disponibles()
¿Qué beneficios trae la herencia en este contexto?
Reutilización de código: Las clases derivadas heredan atributos y métodos comunes.
Mantenimiento: Facilita el mantenimiento y la actualización del código.
Extensibilidad: Permite agregar nuevas clases derivadas con facilidad.
La herencia, junto con la encapsulación y el polimorfismo, es una de las tres características principales de la programación orientada a objetos. La herencia permite crear clases que reutilizan, extienden y modifican el comportamiento definido en otras clases. La clase cuyos miembros se heredan se denomina clase base o padre y la clase que hereda esos miembros se denomina clase derivada o clase hija. Una clase hija solo puede tener una clase padre directa, pero la herencia es transitiva. Si ClassC se deriva de ClassB y ClassB se deriva de ClassA, ClassC hereda los miembros declarados en ClassB y ClassA.
Un ejemplo sencillo de herencia que nos permite conceptualizarlo:
classMamifero:def__init__(self):passdeffeatures(self):print('Tiene pelaje y glandulas mamarias')classPerro(Mamifero):def__init__(self):passdefbark(self):print('Woof!!')defwalking(self):print('Paseando alegre')defeat(self):print('Comiendo contento')classCachorro(Perro):def__init__(self):passdefplay(self):print('Jugando y mordiendo zapatos')cachorro1 = Cachorro()cachorro1.bark()cachorro1.play()cachorro1.features()
muy buen ejemplo, gracias
Resultado:
Woof!!
Jugando y mordiendo zapatos
Tiene pelaje y glandulas mamarias
¿Qué es la Herencia?
Imagina que tienes un coche y una bicicleta. Ambos son vehículos. Aunque son diferentes, tienen cosas en común: ambos pueden moverse, tienen ruedas, y se pueden usar para transportarte. La Herencia es como decir:
Tengo una "clase general" llamada Vehículo (que tiene cosas en común).
Luego, creo "clases específicas" como Coche o Bicicleta, que heredan las cosas que son comunes de la clase Vehículo.
En términos simples, la Herencia permite que una clase (la "clase hija") tome características y comportamientos de otra clase (la "clase padre").
¿Por qué es útil la Herencia?
Reutilización de código: No tienes que escribir las mismas cosas una y otra vez.
Organización: Agrupas comportamientos comunes en una clase base (como Vehiculo) y especificas comportamientos únicos en clases hijas (como Coche y Bicicleta).
El super() en Python es una función que se utiliza principalmente para llamar a métodos y constructores de la clase padre desde la clase hija. Su función más común es cuando queremos extender el comportamiento de la clase padre sin tener que reescribir el código que ya existe en ella.
¿Por qué usamos super()?
Cuando estás en una clase hija, puedes querer heredar o usar el comportamiento de la clase padre sin duplicar código. El uso de super() te permite hacer esto de manera sencilla, invocando métodos de la clase padre. Así puedes agregar cosas nuevas en la clase hija, pero también mantener las características de la clase padre.
Claps!
classCar:def__init__(self, brand,model, price): self.brand = brand
self.model = model
self.price = price
self.is_available =Truedefsell(self):if self.is_available: self.is_available =Falseprint(f"El coche {self.brand}{self.model} ha sido vendido.")else:print(f"El coche {self.brand}{self.model} no esta disponible.")defcheck_availability(self):return self.is_available
defget_price(self):return self.price
classCostumer:def__init__(self, name): self.name = name
self.cars_purchased =[]defbuy_car(self, car):if car.check_availability(): car.sell() self.cars_purchased.append(car)else:print(f"Lo siento, {car.brand}{car.model} no esta disponible.")definquire_car(self, car): availability ="disponible"if car.check_availability()else"no esta disponible"print(f"El coche {car.brand}{car.model} esta {availability} y cuesta {car.price}")classDealership:def__init__(self): self.inventory =[] self.costumers =[]defadd_car(self, car): self.inventory.append(car)print(f"El coche {car.brand}{car.model} ha sido agragado al inventario")defregister_costumer(self, costumer): self.costumers.append(costumer)print(f"El cliente {costumer.name} ha sido registrado")defshow_available_cars(self):print("Coches disponibles en la concesionaria:")for car in self.inventory:if car.check_availability():print(f"{car.brand}{car.model} por {car.price}")# Crear instancias de cochescar1 = Car("Toyota","Corolla","20000")car2 = Car("Honda","Civic","22,000")car3 = Car("Ford","Mustang","35,000")# Crear instancia de clientecostumer1 = Costumer("Carlos")# Crear instancia de concesionaria y registrar coches y clientesdealer = Dealership()dealer.add_car(car1)dealer.add_car(car2)dealer.add_car(car3)dealer.register_costumer(costumer1)#Mostrar coches disponiblesdealer.show_available_cars()# cliente consulta un cochecostumer1.inquire_car(car1)#cliente compra coche costumer1.buy_car(car1)# Mostrar coches disponibles nuevamentedealer.show_available_cars()#cliente intenta comprar un coche ya vendido costumer1.buy_car(car1)
Codigo de la profe antes de inciar la clase
Que rico es codear 😄
Ojalá en las clases siguientes no se incluyan temas como el raise y el NotImplementedError sin explicarlos. Parece un poco que se estuviera transcribiendo un código, pero la explicación?
Total, ya van varios videos donde usan temas que aun no explican.
#Ejercicio hasta el momentoclassVehicle:def__init__(self,brand,model,price): self.brand = brand
self.model = model
self.price = price
self.is_available =Truedefsell(self):if self.is_available: self.is_available =Falseprint(f"El vehiculo {self.brand}. Ha sido vendido.")else:print(f"El vehiculo {self.brand}. No está vendido.")defcheck_available(self):return self.is_available
defget_price(self):return self.price
defstart_engine(self):raise NotImplementedError("Este método debe ser implementado por la subclase")defstop_engine(self):raise NotImplementedError("Este método debe ser implementado por la subclase")classCar(Vehicle):defstart_engine(self):ifnot self.is_available:returnf"El motor del coche {self.brand} está en marcha."else:returnf"El coche {self.brand} no está disponible."defstop_engine(self):ifnot self.is_available:returnf"El motor del coche {self.brand} se ha detenido."else:returnf"El coche {self.brand} no está disponible."
Raise: Básicamente, es una manera en la que podemos lanzar errores, y tener un mayor control en el flujo del software.
Tener en cuenta que raise. Sirve para lanzar o levantar errores y Try/Catch sirve para capturar estor errores y manejarlos.
Debido a que no puedo editar el mensaje anterior. Rectifico que no es try/Catch (Eso es de JS) en python es Try/except
Muchas gracias
La excepción NotImplementedError se utiliza en Python para indicar que un método o función que ha sido definido debe ser implementado por una subclase. Esto es útil en programación orientada a objetos para establecer un contrato que las clases hijas deben cumplir. Por ejemplo:
classVehiculo:definiciar(self):raise NotImplementedError("Este método debe ser implementado por la subclase")classAuto(Vehiculo):definiciar(self):return"El auto ha arrancado"# Usomi_auto = Auto()print(mi_auto.iniciar())# Salida: El auto ha arrancado# vehiculo = Vehiculo()# vehiculo.iniciar() # Esto lanzará NotImplementedError
En este caso, la clase Vehiculo define el método iniciar, pero no lo implementa, forzando a las subclases como Auto a proporcionar su propia implementación.
5:20 Empieza el video
xd
por qué en unas ocasiones se usa el print(f'bla bla bla') y otras el return f"bla bla bla" qué diferencia tiene usar uno u otro?
La diferencia entre print(f'bla bla bla') y return f"texto texto texto" radica en su funcionalidad:
print: Se utiliza para mostrar un mensaje en la consola o terminal. No devuelve ningún valor al programa, solo sirve para visualizar información en pantalla en el momento de la ejecución.
return: Se usa para devolver un valor desde una función al lugar donde fue llamada. Este valor puede ser almacenado en una variable o usado en otras partes del código. A diferencia de print, return no muestra el resultado en la consola a menos que explícitamente se llame después de un print.
Realmente no entendí muy bien el método start_engine
Es decir no entiendo su funcionalidad y tampoco su lógica, porque si no está disponible imprime un mensaje diciendo que el motor está en marcha?
De resto todo lo otro super claro
Hola, es solo para mostrar la abstracción del manejo en la vida real, evidentemente no podremos iniciar el arranque de un motor con POO, pero es una buena manera de ver cómo abstraemos este "Concepto" usando solo un print.
Tengo entendido que tanto la clase Vehículo como la subclase Car deben de ir en el mismo nivel de identación, corríjanme si me equivoco.
Si y por eso le estaba marcando un error.
Sip.
Un método "get" (a menudo llamado getter) es un tipo específico de método cuya función principal es obtener o devolver el valor de uno de los atributos de un objeto.
En la POO, especialmente cuando queremos tener un mejor control sobre cómo se accede o se modifica la información de un objeto, usamos los getters (y sus contrapartes, los setters).
Muchas gracias por tu paráfrasis
El método start_engine es un método que se utiliza en la clase vehículo para indicar que el motor del vehículo debe iniciarse. Este método, al ser abstracto, debe ser implementado en las clases hijas (como auto, bicicleta y camión). Generalmente, verás que al llamarlo se verifica si el vehículo está disponible; si lo está, se inicia el motor y se imprime un mensaje confirmando que el motor ha comenzado a funcionar. Si no está disponible, se indica que no se puede iniciar el motor.
La herencia es un concepto fundamental en la Programación Orientada a Objetos (POO) que permite crear nuevas clases a partir de otras ya existentes. Esto facilita la reutilización de código, ya que una clase hija (o derivada) puede heredar atributos y métodos de una clase padre (o base). Además, puedes agregar nuevos comportamientos o modificar los heredados.
Conceptos clave:
Clase padre (o base): Es la clase de la cual otras clases heredan.
Clase hija (o derivada): Es la clase que hereda de otra, tomando todos sus métodos y atributos, pero que también puede tener características propias.
Excelente paráfrasis
Para heredar una clase en Python, se utiliza la siguiente sintaxis:
En este ejemplo, ClaseHija hereda de ClasePadre, lo que significa que puede acceder a los métodos y atributos de ClasePadre. La función super() se utiliza para llamar al constructor de la clase padre. Esto es fundamental en la programación orientada a objetos, ya que permite reusar código y facilitar la organización de las clases.
Me encanta cuando muestra la sintaxis
La **herencia** en Python es un concepto clave de la Programación Orientada a Objetos (POO) que permite crear una nueva clase a partir de una clase existente. Esto se hace para reutilizar el código, organizar el software en jerarquías lógicas y facilitar la extensión de funcionalidades. A continuación, te explico cómo funciona la herencia en Python con ejemplos:
### 1. **Clase Base o Superclase**
La clase de la que se heredan propiedades y métodos se llama **superclase** o **clase base**. Por ejemplo, consideremos la siguiente clase Animal:
classAnimal:  def \_\_init\_\_(self, nombre):  self.nombre = nombre     def hablar(self):  return f"{self.nombre} hace un sonido."
### 2. **Subclase o Clase Derivada**
La clase que hereda de la superclase se llama **subclase** o **clase derivada**. Esta clase puede heredar los atributos y métodos de la clase base, y además, puede añadir o modificar métodos. Aquí crearemos una subclase Perro que hereda de Animal:
En este ejemplo, la clase Perro hereda el atributo nombre y el método hablar() de la clase Animal, pero sobrescribe el método hablar() para que el perro haga un sonido específico.
### 3. **Uso de la Herencia**
Ahora podemos crear instancias de Perro y usar el método hablar():
Python soporta la **herencia múltiple**, lo que significa que una clase puede heredar de más de una clase base. Por ejemplo:
classMamifero:  def amamantar(self):  return "Este animal amamanta a sus crías."classPerro(Animal, Mamifero):  def hablar(self):  return f"{self.nombre} dice ¡Guau!"
En este caso, Perro hereda tanto de Animal como de Mamifero. Ahora, una instancia de Perro puede usar métodos de ambas clases:
mi\_perro = Perro("Rex")print(mi\_perro.hablar())# Output: Rex dice ¡Guau!print(mi\_perro.amamantar())# Output: Este animal amamanta a sus crías.
### 5. **Función super()**
La función super() se utiliza para llamar a un método de la superclase desde una subclase. Es especialmente útil cuando se sobrescribe un método y se quiere extender su funcionalidad sin reemplazar completamente la implementación original. Por ejemplo:
classGato(Animal):  def hablar(self):  sonido\_original = super().hablar() # Llama al método hablar() de la clase Animal  return f"{sonido\_original} {self.nombre} dice ¡Miau!"
En este ejemplo, el método hablar() de Gato primero llama al método hablar() de Animal y luego añade comportamiento adicional.
mi\_gato = Gato("Mishi")print(mi\_gato.hablar())# Output: Mishi hace un sonido. Mishi dice ¡Miau!
### 6. **Herencia Jerárquica**
Puedes crear jerarquías más complejas donde una clase puede ser la base para otras subclases, formando un árbol de herencia. Por ejemplo:
classVehiculo:  def mover(self):  return "El vehículo se está moviendo."classCoche(Vehiculo):  def mover(self):  return "El coche se está moviendo."classBicicleta(Vehiculo):  pass # Bicicleta hereda mover() de Vehiculo sin modificarlo
### 7. **Resumen**
La herencia en Python te permite:
- Reutilizar el código mediante la creación de nuevas clases basadas en clases existentes.
- Sobrescribir métodos en la subclase para modificar o extender su comportamiento.
- Utilizar super() para invocar métodos de la superclase.
- Implementar herencia múltiple para crear clases que combinan funcionalidades de múltiples clases base.
Este mecanismo es fundamental para organizar y estructurar el código en proyectos de software de manera eficiente y lógica.
classCar: def __init__(self,marca, model, price): self.marca= marca
self.model= model
self.price= price
self.avalible=True def buys(self):if self.avalible==False: self.purshased=Trueprint(f"el carro {self.model} a sido comprado por {self.price}")classUser: def __init__(self, name): self.name= name
self.cars_purshased=[] def sale_cars(self,car):if car.avalible: car.avalible=Falseprint(f"el carro {car.model} a sido vendido por {car.price}")else:print(f"el carro {car.model} no esta disponible, puede que ya haya sido vendido") def buys_cars(self,car):if car.avalible==False: car.avalible=True car.buys() self.cars_purshased.append(car)else:print("el carro no se puede comprar")classconcessionaire: def __init__(self): self.cars_purshased=[] self.users=[] def add_car(self,car): self.cars_purshased.append(car)print(f"se a agregado el carro{car.model}") def Register_user(self,user): self.users.append(user)print(f"Se a añadido el usuario {user.name}") def show_available_cars(self):print("carros disponibles:")for car in self.cars_purshased:if car.avalible:print(f"{car.model} por el precio de {car.price}")carro1 =Car(" Jeep","Compas 2023",120000000)carro2 =Car(" Mazda","Miata 2015",70000000)carro3 =Car(" Renold","captur 2020",93000000)user1 =User("Jesus Sebastian")user2 =User("Jesus Anegl")user3 =User("carechimba")Concessionaire=concessionaire()Concessionaire.add_car(carro2)Concessionaire.add_car(carro1)Concessionaire.add_car(carro3)Concessionaire.Register_user(user1)Concessionaire.Register_user(user2)Concessionaire.Register_user(user3)Concessionaire.show_available_cars()user1.sale_cars(carro1)user3.sale_cars(carro1)user1.buys_cars(carro1)user1.buys_cars(carro1)user3.sale_cars(carro1)```classCar: def \_\_init\_\_(self,marca, model, price): self.marca= marca self.model= model self.price= price self.avalible=True def buys(self):if self.avalible==False: self.purshased=True print(f"el carro {self.model} a sido comprado por {self.price}")classUser: def \_\_init\_\_(self, name): self.name= name self.cars\_purshased = \[] def sale\_cars(self,car):if car.avalible: car.avalible=False print(f"el carro {car.model} a sido vendido por {car.price}")else:print(f"el carro {car.model} no esta disponible, puede que ya haya sido vendido") def buys\_cars(self,car):if car.avalible==False: car.avalible=True car.buys() self.cars\_purshased.append(car)else:print("el carro no se puede comprar")classconcessionaire: def \_\_init\_\_(self): self.cars\_purshased = \[] self.users= \[] def add\_car(self,car): self.cars\_purshased.append(car)print(f"se a agregado el carro{car.model}") def Register\_user(self,user): self.users.append(user)print(f"Se a añadido el usuario {user.name}") def show\_available\_cars(self):print("carros disponibles:")for car in self.cars\_purshased:if car.avalible:print(f"{car.model} por el precio de {car.price}")carro1 =Car(" Jeep","Compas 2023",120000000)carro2 =Car(" Mazda","Miata 2015",70000000)carro3 =Car(" Renold","captur 2020",93000000)user1 =User("Jesus Sebastian")user2 =User("Jesus Anegl")user3 =User("carechimba")Concessionaire=concessionaire()Concessionaire.add\_car(carro2)Concessionaire.add\_car(carro1)Concessionaire.add\_car(carro3)Concessionaire.Register\_user(user1)Concessionaire.Register\_user(user2)Concessionaire.Register\_user(user3)Concessionaire.show\_available\_cars()user1.sale\_cars(carro1)user3.sale\_cars(carro1)user1.buys\_cars(carro1)user1.buys\_cars(carro1)user3.sale\_cars(carro1)
Holaa, les comparto mi proyecto de la concesionaria "Rápidos y Furiosos", me tomo un poco comprender el tema de la funciones, pero poniéndolo en práctica lo entiendo mucho mejor, no se rindan si pasan por los mismo. ^^
classVehiculo: def __init__(self, marca, modelo, año, precio): self.marca= marca
self.modelo= modelo
self.año= año
self.precio= precio
self.available=True def mostrar_vehiculos(self):return f"Auto {self.marca} - {self.modelo} del año {self.año}, precio {self.precio}." def estado(self):if self.available: self.available=Falseprint(f"El auto {self.marca} - {self.modelo} del año {self.año}, no se encuentra disponible")else:print(f"El auto {self.marca} - {self.modelo} del año {self.año}, se encuentra disponible")classConcesionaria: def __init__(self, nombre_con): self.nombre_con= nombre_con
self.vehiculos=[] def agregar_vehiculo(self, vehiculo): self.vehiculos.append(vehiculo) def mostrar_vehiculos(self):if self.vehiculos:for vehiculo in self.vehiculos:print(vehiculo.mostrar_vehiculos())else:print(f"{self.nombre_con}, no tiene el vehiculo disponible.") def vender_vehiculo(self, vehiculo, comprador):if vehiculo in self.vehiculos:if comprador.realizar_pago(vehiculo.precio): self.vehiculos.remove(vehiculo) comprador.agregar_vehiculo(vehiculo)print(f"Vehiculo {vehiculo.mostrar_vehiculos()}, a {comprador.nombre}")else:print("No se pudo concretar la venta, por problemas con el pago")else:print(f"El {vehiculo.mostrar_vehiculos()}, no se encuentra en stock.")classUser: def __init__(self, nombre, saldo): self.nombre= nombre
self.saldo= saldo
self.vehiculos=[] def agregar_vehiculo(self, vehiculo): self.vehiculos.append(vehiculo) def mostrar_vehiculos(self):if self.vehiculos:for vehiculo in self.vehiculos:print(vehiculo.mostrar_vehiculos())else:print(f"{self.nombre}, no tiene vehiculo.") def tiene_saldo_suficiente(self, precio):return self.saldo>= precio
def realizar_pago(self, monto):if self.tiene_saldo_suficiente(monto): self.saldo-= monto
print(f"Pago realizado por: ${monto}. Saldo restante: ${self.saldo}. ")returnTrueelse:print(f"Sin saldo suficiente")returnFalse#Crear vehiculo
vehiculo_1 =Vehiculo("Toyota","Yaris","2013",20000)vehiculo_2 =Vehiculo("Audi","Corola","2020",80000)vehiculo_3 =Vehiculo("Ferrari","escarabajo","2024",90000)#Crear concesionaria
concesionaria =Concesionaria("Rapidos y Furiosos")concesionaria.agregar_vehiculo(vehiculo_1)concesionaria.agregar_vehiculo(vehiculo_2)concesionaria.agregar_vehiculo(vehiculo_3)#Crear comprador
comprador =User("Mari",400000)#Mostrar vehiculos de la concesionaria
concesionaria.mostrar_vehiculos()#Vender vehiculo de la concesionaria
concesionaria.vender_vehiculo(vehiculo_3, comprador)# Mostrar vehículos del comprador
comprador.mostrar_vehiculos()```classVehiculo: def \_\_init\_\_(self, marca, modelo, año, precio): self.marca= marca self.modelo= modelo self.año= año self.precio= precio self.available=True  def mostrar\_vehiculos(self):return f"Auto {self.marca} - {self.modelo} del año {self.año}, precio {self.precio}." def estado(self):if self.available: self.available=Falseprint(f"El auto {self.marca} - {self.modelo} del año {self.año}, no se encuentra disponible")else:print(f"El auto {self.marca} - {self.modelo} del año {self.año}, se encuentra disponible")classConcesionaria: def \_\_init\_\_(self, nombre\_con): self.nombre\_con = nombre\_con self.vehiculos= \[]  def agregar\_vehiculo(self, vehiculo): self.vehiculos.append(vehiculo)  def mostrar\_vehiculos(self):if self.vehiculos:for vehiculo in self.vehiculos:print(vehiculo.mostrar\_vehiculos())else:print(f"{self.nombre\_con}, no tiene el vehiculo disponible.") def vender\_vehiculo(self, vehiculo, comprador):if vehiculo in self.vehiculos:if comprador.realizar\_pago(vehiculo.precio): self.vehiculos.remove(vehiculo) comprador.agregar\_vehiculo(vehiculo)print(f"Vehiculo {vehiculo.mostrar\_vehiculos()}, a {comprador.nombre}")else:print("No se pudo concretar la venta, por problemas con el pago")else:print(f"El {vehiculo.mostrar\_vehiculos()}, no se encuentra en stock.")classUser: def \_\_init\_\_(self, nombre, saldo): self.nombre= nombre self.saldo= saldo self.vehiculos= \[] def agregar\_vehiculo(self, vehiculo): self.vehiculos.append(vehiculo) def mostrar\_vehiculos(self):if self.vehiculos:for vehiculo in self.vehiculos:print(vehiculo.mostrar\_vehiculos())else:print(f"{self.nombre}, no tiene vehiculo.")  def tiene\_saldo\_suficiente(self, precio):return self.saldo>= precio def realizar\_pago(self, monto):if self.tiene\_saldo\_suficiente(monto): self.saldo-= monto print(f"Pago realizado por: ${monto}. Saldo restante: ${self.saldo}. ")returnTrueelse:print(f"Sin saldo suficiente")returnFalse #Crear vehiculo
vehiculo\_1 =Vehiculo("Toyota","Yaris","2013",20000)vehiculo\_2 =Vehiculo("Audi","Corola","2020",80000)vehiculo\_3 =Vehiculo("Ferrari","escarabajo","2024",90000)\#Crear concesionaria
concesionaria =Concesionaria("Rapidos y Furiosos")concesionaria.agregar\_vehiculo(vehiculo\_1)concesionaria.agregar\_vehiculo(vehiculo\_2)concesionaria.agregar\_vehiculo(vehiculo\_3)\#Crear compradorcomprador =User("Mari",400000)\#Mostrar vehiculos de la concesionariaconcesionaria.mostrar\_vehiculos()\#Vender vehiculo de la concesionariaconcesionaria.vender\_vehiculo(vehiculo\_3, comprador)\# Mostrar vehículos del compradorcomprador.mostrar\_vehiculos() 
Que gran proyecto, te quedó recool.
Hola! Para la funcion show_available_cars cambie la logica hacia diccionarios. La idea es poder incluir carros usando las placas para evitar tener dos carros identicos (i.e. misma placa) en el inventario
raise: Lanzar una excepción
Se usa para provocar un error de forma intencional.
Es útil cuando quieres detener el programa si ocurre una condición no válida.
try/except: Capturar y manejar una excepción
Se usa para atrapar errores que podrían ocurrir y evitar que el programa se detenga.
Permite dar una respuesta alternativa o mostrar un mensaje amigable.