Aquí veremos la diferencia entre:
métodos regulares (regular methods)
métodos de clase (class methods)
métodos estáticos (static methods)
Los métodos regulares toman como primer argumento la instancia, self
.
Para crear métodos de clase, a la larga lo que queremos es que el argumento sea la clase.
Para crearlo, hay que usar decoradores (decorators).
Hemos visto una introducción a los decoradores antes: recordar que es como un envoltorio (wrapper) de la función que se pone debajo.
Lo que básicamente hace el decorador es modificar la funcionalidad del método para que reciba como primer argumento la clase, y no la instancia.
Vamos a crear un método de class para la tasa de crecimiento del salario.
class Empleados:
tasa_incremento_salarial = 1.1
num_de_emps = 0
def __init__(self, nombre, apellido, salario):
self.nombre = nombre
self.apellido = apellido
self.salario = salario
self.email = nombre + "." + apellido + "@emp.com"
Empleados.num_de_emps += 1
def nombre_completo(self):
print(f"{self.nombre} {self.apellido}")
def incremento_salarial(self):
self.salario = int(self.salario * self.tasa_incremento_salarial)
@classmethod
def set_incremento(cls, tasa):
cls.tasa_incremento_salarial = tasa
Si simplemente ejectutamos lo que teniamos y presentamos las variables de clase y de instancia tenemos:
emp_1 = Empleados("Daniel", "Miles", 100000)
emp_2 = Empleados("Ines", "Gonzalez", 150000)
print(Empleados.tasa_incremento_salarial)
print(emp_1.tasa_incremento_salarial)
print(emp_2.tasa_incremento_salarial)
1.1 1.1 1.1
Es natural que obtengamos una tasa de crecimiento del 10% pues la variable de clase, tasa_incremento_salarial
Pero si queremos cambiar esta cantidad, simplemente deberíamos hacer
Empleados.set_incremento(1.07)
print(Empleados.tasa_incremento_salarial)
print(emp_1.tasa_incremento_salarial)
print(emp_2.tasa_incremento_salarial)
1.07 1.07 1.07
El class method afecta a todas las instancias de esa clase.
Hay que tener en cuenta que el class method que hemos implementado hace lo mismo que
Empleados.tasa_incremento_salarial = 1.07
Por ejemplo: si los datos, por alguna cuestión, bien en un formato digital complicado y no quiero corregirlos a mano
emp_str_1 = "Miguel-Cervantes-50000"
emp_str_2 = "Alumena-Grandes-75000"
Si quiero insertar estos nombres en mi clase, debería primero separarlos para que la información tenga el mismo formato que la construcción de la instancia
nombre, apellido, salario = emp_str_1.split("-")
nombre, apellido,salario
('Miguel', 'Cervantes', '50000')
Ahora podriamos crear un nuevo empleado.
nuevo_emp = Empleados(nombre, apellido, salario)
nuevo_emp.email
'Miguel.Cervantes@emp.com'
Pero si esto fuera algo común, podriamos crear un nuevo constructor de instancias que lo tenga en cuenta Pero podriamos crear un nuevo constructor
class Empleados:
tasa_incremento_salarial = 1.1
num_de_emps = 0
def __init__(self, nombre, apellido, salario):
self.nombre = nombre
self.apellido = apellido
self.salario = salario
self.email = nombre + "." + apellido + "@emp.com"
Empleados.num_de_emps += 1
def nombre_completo(self):
print(f"{self.nombre} {self.apellido}")
def incremento_salarial(self):
self.salario = int(self.salario * self.tasa_incremento_salarial)
@classmethod
def set_incremento(cls, tasa):
cls.tasa_incremento_salarial = tasa
@classmethod
# por convencion: empiezan con from
def from_string(cls, emp_str):
nombre, apellido, salario = emp_str.split("-")
# debemos devolverlo para crear este empleado
return cls(nombre, apellido, salario)
emp_str_1 = "Miguel-Cervantes-50000"
emp_str_2 = "Alumena-Grandes-75000"
nuevo_emp_2 = Empleados.from_string(emp_str_2)
nuevo_emp_2.email
'Alumena.Grandes@emp.com'
regular methods: self
as argument
class method: cls
as argumento
static methods: no pasan nada automaticamente
Para crear un static methods usamos tambien un decorator
Vamos a crear un static method
que me diga si el dia actual es un dia de trabajo o no.
class Empleados:
tasa_incremento_salarial = 1.1
num_de_emps = 0
def __init__(self, nombre, apellido, salario):
self.nombre = nombre
self.apellido = apellido
self.salario = salario
self.email = nombre + "." + apellido + "@emp.com"
Empleados.num_de_emps += 1
def nombre_completo(self):
print(f"{self.nombre} {self.apellido}")
def incremento_salarial(self):
self.salario = int(self.salario * self.tasa_incremento_salarial)
@classmethod
def set_incremento(cls, tasa):
cls.tasa_incremento_salarial = tasa
@classmethod
# por convencion: empiezan con from
def from_string(cls, emp_str):
nombre, apellido, salario = emp_str.split("-")
# debemos devolverlo para crear este empleado
return cls(nombre, apellido, salario)
@staticmethod
def es_dia_laboral(dia):
# Si es sabado,o domingo, no es laborable
if dia.weekday() == 5 or dia.weekday() == 6:
return False
return True
import datetime
dia = datetime.date(2024,5,23)
Empleados.es_dia_laboral(dia)
True
El concepto de cuenta bancaria en un programa es un buen candidato para una clase.
La cuenta tiene algunos datos, normalmente el nombre del titular de la cuenta, el número de cuenta y el saldo actual.
Tres cosas que podemos hacer con una cuenta es retirar dinero, ingresar dinero en la cuenta, e imprimir los datos de la cuenta.
1.- Crear una clase que permita identificar al cliente con su nombre, numero de cuenta y saldo. Además, le permita retirar o dinero.
2.- Una vez creada la clase, al gerente quiere tener un control del numero de cuentas creadas
3.- Ahora al gerente se le ocurre tener informacion sobre fechas: creación, deposito y retiro.
4.- Ahora al genente se le ocurre premiar la fidelización con un tipo de interes fijo para todos los clientes en funcion del saldo medio que han tenido desde el inicio de la cuenta hasta ahora.
Punto 1
class Cuenta(object):
def __init__(self, nombre, numero_cuenta, saldo_inicial):
self.nombre = nombre
self.no = numero_cuenta
self.saldo = saldo_inicial
def deposito(self, cantidad):
self.saldo += cantidad
def retiro(self, cantidad):
if self.saldo >= cantidad:
self.saldo -= cantidad
else:
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos y quiere retirar {cantidad}")
def impresion(self):
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos")
cuenta1 = Cuenta("jose artigas", 1111, 10)
cuenta1.impresion()
JOSE ARTIGAS tiene un saldo de 10
Punto 2
class Cuenta(object):
total_cuentas = 0
def __init__(self, nombre, numero_cuenta, saldo_inicial):
self.nombre = nombre
self.no = numero_cuenta
self.saldo = saldo_inicial
Cuenta.total_cuentas += 1
def deposito(self, cantidad):
self.saldo += cantidad
def retiro(self, cantidad):
if self.saldo >= cantidad:
self.saldo -= cantidad
else:
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos y quiere retirar {cantidad}")
def impresion(self):
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos")
Punto 3
import datetime
class Cuenta(object):
total_cuentas = 0
def __init__(self, nombre, numero_cuenta, saldo_inicial, fecha_creacion):
self.nombre = nombre
self.no = numero_cuenta
self.saldo = saldo_inicial
self.fecha_creacion = datetime.datetime.strptime(fecha_creacion, "%Y/%m/%d")
Cuenta.total_cuentas += 1
def deposito(self, cantidad, fecha_deposito):
self.saldo += cantidad
self.fecha_deposito = datetime.datetime.strptime(fecha_deposito, "%Y/%m/%d")
def retiro(self, cantidad, fecha_retiro):
if self.saldo >= cantidad:
self.saldo -= cantidad
self.fecha_retiro = datetime.datetime.strptime(fecha_retiro, "%Y/%m/%d")
else:
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos y quiere retirar {cantidad}")
def impresion(self):
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos")
Punto 4
import datetime
class Cuenta(object):
total_cuentas = 0
tasa_fidelizacion = 1.05
def __init__(self, nombre, numero_cuenta, saldo_inicial, fecha_creacion):
self.nombre = nombre
self.no = numero_cuenta
self.saldo = saldo_inicial
self.fecha_creacion = datetime.datetime.strptime(fecha_creacion, "%Y/%m/%d").date()
Cuenta.total_cuentas += 1
def deposito(self, cantidad, fecha_deposito):
self.saldo += cantidad
self.fecha_deposito = datetime.datetime.strptime(fecha_deposito, "%Y/%m/%d").date()
def retiro(self, cantidad, fecha_retiro):
if self.saldo >= cantidad:
self.saldo -= cantidad
self.fecha_retiro = datetime.datetime.strptime(fecha_retiro, "%Y/%m/%d").date()
else:
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos y quiere retirar {cantidad}")
def impresion(self):
return print(f"{self.nombre.upper()} tiene un Saldo de {self.saldo} pesos")
@classmethod
def tasa_fidel(cls, tasa):
cls.tasa_fidelizacion = tasa
def premio_fidelizacion(self):
ahora = datetime.datetime.now().date()
tiempo = ahora - self.fecha_creacion
saldo_medio = self.saldo / tiempo.days
self.deposito(saldo_medio*(1 + self.tasa_fidelizacion), ahora.strftime("%Y/%m/%d"))