class Deposito:
def __init__(self, duracion, cuantia, tasa, activo): # método constructor con los atributos de instancia
self.duracion = duracion # duración del depósito bancario en días
self.cuantia = cuantia # importe en euros
self.tasa = tasa # tipo de interés efectivo anual, expresado en tanto por uno
self.activo = activo # True si aún no ha llegado a vencimiento, False si es un depósito antiguo ya vencido
self.moneda = "€" # atributo de clase
self.interes = "efectivo anual" # atributo de clase
def montante(self): # un método que calcula el montante final a devolver
return self.cuantia * (1 + self.tasa)**(self.duracion/365)
def vencimiento(self):
if self.activo: return "no"
else: return "si"
d1 = Deposito(480, 50_000, 0.01, False) # instanciamos los tres depósitos
d2 = Deposito(180, 10_000, 0.02, True)
d3 = Deposito(360, 120_000, 0.03, True)
print(f"El importe invertido en el depósito d1 es {d1.cuantia} {d1.moneda}.") # probando el atributo cuantía
print(f"El montante a devolver en el depósito d1 asciende a {round(d1.montante(),2)} {d1.moneda}.") # el método montante
print()
print(f"El depósito d1 ha llegado a vencimiento: {not d1.activo}")
print(f"El depósito d2 ha llegado a vencimiento: {not d2.activo}")
print(f"El depósito d3 ha llegado a vencimiento: {not d3.activo}")
print()
print("OTRA FORMA DE EXPRESARLO (usando el método vencimiento)")
print(f"\tEl depósito d1 {d1.vencimiento()} ha llegado a vencimiento.")
print(f"\tEl depósito d2 {d2.vencimiento()} ha llegado a vencimiento.")
print(f"\tEl depósito d3 {d3.vencimiento()} ha llegado a vencimiento.")
Sumar una serie indeterminada de sumandos en una función.
def suma(a,b): # esto es una suma solo de dos argumentos
return a+b
print(suma(5,4))
def sumar(*valores): # en este caso, al poner asterisco, podemos sumar un número indeterminado de argumentos
total = 0
for valor in valores:
total += valor
return total
print(sumar(10,20,30)) # podemos sumar tres argumentos
print(sumar(1,2,3,4,5,6)) # podemos sumar seis argumentos, o el número que queramos usando la misma función
Ordenar un diccionario por sus valores de mayor a menor.
dict = {"C#":100, "Python":900, "R":700, "Java":300}
lista = sorted(dict.items(), key=lambda x: x[1], reverse=True)
for i in lista:
print(i[0],"\t", i[1])
Fuente: EEUU y la UE ante el desafío geoestratégico de China y Rusia
class Pais:
def __init__(self,nombre, pib):
self.nombre = nombre
self.pib = pib
def ordena(self,*paises): # El asterisco toma un nº indeterminado de argumentos
lista_nombre = [self.nombre]
lista_pib = [self.pib]
for pais in paises:
lista_nombre.append(pais.nombre)
lista_pib.append(pais.pib)
d = dict(zip(lista_nombre, lista_pib)) # diccionario
#print(d)
lista = sorted(d.items(), key=lambda x: x[1], reverse=True)
for i in lista:
print(i[0],"\t", i[1])
p1 = Pais("China", 14.8) # instanciamos un objeto País
p2 = Pais("UE", 13.9) # instanciamos otro objeto País
p3 = Pais("EEUU", 20.8) # instanciamos el tercer objeto País
print("{:>10}".format("RANKING"))
print("="*14)
p1.ordena(p2,p3) # ordena p1, p2 y p3
#p2.ordena(p1,p3) # hace exactamente lo mismo
#p3.ordena(p2,p3) # hace exactamente lo mismo
Usar el doble asterisco.
El doble asterisco se utiliza para tratar un número indeterminado de elementos de un diccionario.
El doble asterisco se utiliza para desempaquetar diccionarios.
Al tratarse de un diccionario, el orden de los parámetros no importa.
def letras(**kwargs):
return kwargs
letras(A=1, B=2, C=3, D=4) # el resultado es un diccionario {'A': 1, 'B': 2, 'C': 3, 'D': 4}
def poblacion(**kwargs):
for key, value in kwargs.items():
print(f"En 2012 La población de {key} se estima que fue de {value} personas.")
poblacion(China=1_343_239_923, India=1_205_073_612, UE=443_108_346, EEUU=313_847_465)
Usar el doble asterisco en POO.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class Persona:
def __init__(self, edad, nombre):
self.edad = edad
self.nombre = nombre
print(f"Hola, soy {self.nombre} de {self.edad} años.")
def hablar(self, **palabras):
for palabra in palabras:
print(f"{self.nombre}: {palabras[palabra]}")
juanjo = Persona(nombre="Juan José", edad=30)
juanjo.hablar(t1="hola", t2="encantado de estar aquí")
Redondear y poner separador de miles.
a = 1234.576
print(a)
b = round(a,2) # redondeando a dos decimales
print(b)
print("{:,}".format(b)) # formato inglés
print("{:,}".format(b).replace(',','~').replace('.',',').replace('~','.')) # formato español
Crear una clase con algunos atributos y procurar que sean privados.
Crear la clase Scoring para determinar si se concederá o no un préstamo en función de una serie de características personales y financieras del cliente.
El Credit Scoring es el conjunto de técnicas estadísticas que permiten evaluar una solicitud de crédito y determinar si la operación financiera llegará a ser viable o no.
Veamos dos métodos de resolución del reto.
__atributo
.@property
Usando un prefijo de doble barra baja en los nombres de los atributos se intenta que los atributos así definidos sean privados. Sirve para avisar a otros programadores o a nosotros mismos, en el futuro cuando revisemos el código, que ese atributo queremos que no sea accesible desde fuera de la propia clase.
La realidad es que esto solo es un intento, una declaración de intenciones, ya que un programador experimentado podría acceder a esos atributos desde fuera de la clase. Por eso decimos que es un 'intento' que pretende hacer privados estos atributos.
class Scoring:
def __init__(self, nombre_cliente, edad, importe_solicitado, patrimonio, deudas, ingresos_anuales):
self.nombre = nombre_cliente # atributo público
self.edad = edad # atributo público
self.__importe = importe_solicitado # atributo que pretende ser privado
self.__patrimonio = patrimonio # atributo que pretende ser privado
self.__deudas = deudas # atributo que pretende ser privado
self.__ingresos = ingresos_anuales # atributo que pretende ser privado
def importe_concedido(self):
if 30 <= self.edad <= 50:
coef = 0.5 # en ese rango de edad se concede el 50% del patrimonio neto disponible estimado
else:
coef = 0.4 # fuera de ese rango de edad se concede solo el 40%
concedido = coef*((self.__patrimonio-self.__deudas)+self.__ingresos-self.__importe)
concedido = min(concedido,self.__importe) # no se concede más del importe solicitado
concedido = max(concedido, 0) # la cantidad concedida nunca es negativa
concedido = round(concedido) # redondeamos a cero decimales
return "{:,} €".format(concedido) # ponemos separador de miles
c1 = Scoring("Ana", 35, 30000, 200000, 150000, 35000) # instanciamos el objeto c1 (cliente 1)
print(f"{c1.nombre} después del estudio, hemos podido concederle {c1.importe_concedido()}")
#c1.nombre #es un atributo público, podemos acceder a él desde fuera de la clase
#c1.importe_concedido() #es un método público. Al ser método lleva los paréntesis ()
# si intentamos acceder al patrimonio de Ana desde fuera de la clase nos dará error
# pero si hemos podido acceder a su nombre porque no lleva los dos guiones bajos precediendo al atributo
#c1.__patrimonio # para ver el error quite el símbolo # del comentario
#c1.patrimonio # tampoco funciona, da error
print(c1.nombre) # si puedo acceder al nombre pq no es privado
print(c1.edad) # si puedo acceder a la edad pq no es privado
# pero un programador experimentado podría saber que el atributo patrimonio ahora se ha renombrado como
# _Scoring__patrimonio y podría consultarlo, obteniendo una información sensible que no debiera ser pública
c1._Scoring__patrimonio # 200000, vemos que ahora funciona y no da error
dir(c1) # listado con los nombres de atributos y métodos del objeto c1
# podemos acceder a la variable patrimonio y modificarlo desde fuera, haciendo trampas
c1._Scoring__patrimonio = 500000
c1._Scoring__patrimonio
# de esta forma si ahora volvemos a calcular el importe_concedido veremos que sube nuestro límite
c1.importe_concedido() # 30000, ahora nos pueden conceder un mayor importe en el préstamo solicitado, TRAMPA
Haciendo privados los atributos usando decoradores con @property
class Scoring:
def __init__(self, nombre_cliente, edad, importe_solicitado, patrimonio, deudas, ingresos_anuales):
self.nombre = nombre_cliente
self.edad = edad
self.__importe = importe_solicitado
self.__patrimonio = patrimonio
self.__deudas = deudas
self.__ingresos = ingresos_anuales
@property # usando un decorador como método getter
def patrimonio(self):
print("Se ha llamado al método getter")
return "El patrimonio es privado"
@patrimonio.setter # creando el método setter
def patrimonio(self, valor):
self.__patrimonio = valor
print("El patrimonio ha sido modificado a", self.__patrimonio) # opcionalmente ponemos un print informativo
print("Se ha enviado un informe al supervisor para comprobar este cambio.")
def importe_concedido(self):
if 30 <= self.edad <= 50:
coef = 0.5
else:
coef = 0.4
concedido = coef*((self.__patrimonio-self.__deudas)+self.__ingresos-self.__importe)
concedido = min(concedido,self.__importe)
concedido = max(concedido, 0)
concedido = round(concedido)
return "{:,} €".format(concedido)
c1 = Scoring("Ana", 35, 30000, 200000, 150000, 35000)
print(f"{c1.nombre} después del estudio, hemos podido concederle {c1.importe_concedido()}")
# accedemos al método setter para cambiar el patrimonio
c1.patrimonio = 170000 # usamos directamente el atributo 'patrimonio' y nos deja
# muestra la frase optativa informando de que el patrimonio ha sido cambiado
# el setter podría introducir más lógica de programación para controlar los cambios que se pretendan introducir
c1.importe_concedido()