Skip to content

Commit ac2554f

Browse files
authored
Merge pull request mouredev#7152 from mrodara/mrodara/main
#21-Python
2 parents d8c4d53 + b412f85 commit ac2554f

File tree

5 files changed

+453
-0
lines changed

5 files changed

+453
-0
lines changed
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
### CALLBACKS EN PYTHON
2+
3+
'''
4+
Un callback es simplemente una función que:
5+
6+
Se pasa como argumento a otra función.
7+
Es llamada dentro de esa función en un momento determinado.
8+
'''
9+
10+
# Definimos una función callback
11+
#def saludo(name: str) -> None:
12+
# print(f"Hola {name}")
13+
#
14+
## Función principal que usará el callback
15+
#def procesar_saludo(name: str, my_callback) -> None:
16+
# print("Procesando saludo...")
17+
# my_callback(name)
18+
# print("Saludo procesado.")
19+
#
20+
#procesar_saludo("Brais", saludo)
21+
22+
23+
### EJERCICIO EXTRA
24+
import asyncio #Vamos a trabajar con procesos
25+
from random import randint #Para generar los tiempo aleatorios
26+
27+
# Funciones callback
28+
async def order_confirmed(plate_name: str) -> None:
29+
print(f"La comanda para el plato: {plate_name} está confirmada")
30+
await asyncio.sleep(randint(1,10)) # Generamos un tiempo aleatorio entre 1 y 10
31+
32+
async def order_ready(plate_name: str) -> None:
33+
print(f"La comanda para el plato: {plate_name} está lista")
34+
await asyncio.sleep(randint(1,10)) # Generamos un tiempo aleatorio entre 1 y 10
35+
36+
async def order_delivered(plate_name: str) -> None:
37+
print(f"La comanda para el plato: {plate_name} está entregada")
38+
await asyncio.sleep(randint(1,10)) # Generamos un tiempo aleatorio entre 1 y 10
39+
40+
# Función principal
41+
async def procesar_pedido(plate_name: str, cb_confirmed, cb_ready, cb_delivered) -> None:
42+
print(f"Procesando pedido de {plate_name}...")
43+
#await asyncio.sleep(1)
44+
await cb_confirmed(plate_name)
45+
#await asyncio.sleep(1)
46+
await cb_ready(plate_name)
47+
#await asyncio.sleep(1)
48+
await cb_delivered(plate_name)
49+
#await asyncio.sleep(1)
50+
print(f"Pedido de {plate_name} procesado.")
51+
52+
# Ejecución asíncrona
53+
async def main() -> None:
54+
await asyncio.gather(
55+
procesar_pedido("Pizza", order_confirmed, order_ready, order_delivered),
56+
procesar_pedido("Hamburguesa", order_confirmed, order_ready, order_delivered),
57+
procesar_pedido("Kebap", order_confirmed, order_ready, order_delivered)
58+
)
59+
60+
# Ejecutar la función principal
61+
asyncio.run(main())
62+
63+
### FIN EJERCICIO EXTRA
64+
65+
### FIN CALLBACKS EN PYTHON
66+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
### FUNCIONES DE ORDEN SUPERIOR EN PYTHON
2+
3+
'''
4+
Una función de orden superior es aquella que:
5+
Acepta una función como argumento.
6+
Devuelve otra función como resultado.
7+
O ambas cosas.
8+
'''
9+
10+
# Ejemplo de función que acepta otra como argumento:
11+
def calculator(x: float, y: float, operation) -> float:
12+
return operation(x, y)
13+
14+
def sum(a: float, b: float) -> float:
15+
return a + b
16+
17+
def product(a: float, b: float) -> float:
18+
return a * b
19+
20+
print(calculator(10,20, sum)) # Salida 30
21+
print(calculator(10,20, product)) # Salida 200
22+
23+
# Ejemplo devolviendo otra función como resultado (lambda):
24+
def new_calculator(operation):
25+
if operation.lower() == "sum":
26+
return lambda a, b: a + b
27+
elif operation.lower() == "product":
28+
return lambda a, b: a * b
29+
else:
30+
return lambda a, b: None
31+
32+
my_sum = new_calculator("sum")
33+
my_product = new_calculator("product")
34+
35+
print(my_sum(5,5)) # Salida 10
36+
print(my_product(5,5)) # Salida 25
37+
38+
# Python ofrece varias funciones de orden superior predefinidas, como map, filter, y reduce.
39+
40+
my_list = [i for i in range(1,11)]
41+
42+
square = map(lambda x: x**2, my_list)
43+
print(list(square))
44+
45+
pairs = filter(lambda x: x%2 == 0, my_list)
46+
47+
print(list(pairs))
48+
49+
# Para reduce necesitamos importar functools
50+
from functools import reduce
51+
52+
sum = reduce(lambda x, y: x + y, my_list)
53+
print(sum) # Salida 55
54+
55+
### EJERCICIO EXTRA
56+
students = [
57+
{
58+
"name": "Manuel Rodriguez",
59+
"birth_date": "2002-05-14",
60+
"grades": [8.5, 7.0, 9.0, 6.5]
61+
},
62+
{
63+
"name": "Lucia Perez",
64+
"birth_date": "2003-11-22",
65+
"grades": [7.5, 9.0, 8.0, 9.5]
66+
},
67+
{
68+
"name": "Pedro Sanchez",
69+
"birth_date": "2001-08-05",
70+
"grades": [6.0, 5.5, 7.0, 6.5]
71+
},
72+
{
73+
"name": "Ana Fernandez",
74+
"birth_date": "2004-01-30",
75+
"grades": [9.0, 8.5, 9.5, 10.0]
76+
},
77+
{
78+
"name": "Carlos Garcia",
79+
"birth_date": "2002-07-19",
80+
"grades": [7.0, 7.5, 6.0, 8.0]
81+
}
82+
]
83+
84+
# Promedio de calificaciones:
85+
def analysis(iterable: list, operation):
86+
return operation(iterable)
87+
88+
def avg(iterable: list) ->list:
89+
90+
avg_students = []
91+
92+
for element in iterable:
93+
avg = 0
94+
for grade in element["grades"]:
95+
avg += grade
96+
avg /= len(element["grades"])
97+
98+
avg_students.append({
99+
"name": element["name"],
100+
"avg": avg
101+
})
102+
103+
return avg_students
104+
105+
avg_students = analysis(students, avg)
106+
107+
print(list(avg_students))
108+
109+
# Aprovechamos la lista avg_students para obtener los mejores estudiantes, en este caso usaremos filter
110+
best_students = filter(lambda x: x['avg'] >=9 and x['avg']<=10, avg_students)
111+
print(list(best_students))
112+
113+
# Lista de estudiantes ordenada por fecha de nacimiento
114+
students_by_birthday = sorted(students, key=lambda p: p['birth_date'])
115+
print(list(students_by_birthday))
116+
117+
# Obtención de la nota más alta de entre todas las obtenidas por los estudiantes
118+
max_grade = reduce(lambda x,y: max(x,y), [grade for student in students for grade in student["grades"]])
119+
print(max_grade)
120+
121+
### FIN EJERCICIO EXTRA
122+
123+
124+
### FIN FUNCIONES DE ORDEN SUPERIOR EN PYTHON
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#### PATRONES DE DISEÑO: SINGLETON
2+
3+
'''
4+
El patrón Singleton es un patrón de diseño que asegura que una clase tenga una única instancia en todo el programa
5+
y proporciona un punto de acceso global a esa instancia. Es útil en casos como la gestión de configuraciones,
6+
recursos compartidos (como conexiones a bases de datos) o registros de logs.
7+
8+
Python ofrece varias formas de implementar este patrón, la más sencilla es usando variables de clase
9+
'''
10+
11+
# Implementación básica: usando variables de clase
12+
class Configuration:
13+
_instance = None # Variable de clase para almacenar la única instancia
14+
15+
# Método para controla la construcción de la instancia
16+
def __new__(cls, *args, **kwargs):
17+
if not cls._instance:
18+
cls._instance = super().__new__(cls, *args, **kwargs) #Nueva instancia usando clase base
19+
cls._instance.settings = {} #Creamos un diccionario para almacenar nuestra configuración
20+
21+
return cls._instance # Devolvemos la instáncia única (nueva o ya creada)
22+
23+
def set(self, key, value):
24+
self.settings[key] = value
25+
26+
def get(self, key):
27+
return self.settings.get(key, None)
28+
29+
# Uso de singleton
30+
config1 = Configuration()
31+
config2 = Configuration()
32+
33+
config1.set("db_host", "192.168.20.10")
34+
config1.set("db_name", "my_db")
35+
config1.set("db_user", "user_db")
36+
config1.set("port", 3306)
37+
38+
print(config1.get("db_host")) # 192.168.20.10
39+
print(config2.get("db_host"))
40+
41+
print(config1 is config2)
42+
43+
### EJERCICIO EXTRA
44+
class Session():
45+
__instance = None
46+
47+
def __new__(cls, *args, **kwargs):
48+
if not cls.__instance:
49+
cls.__instance = super().__new__(cls, *args, **kwargs)
50+
cls.__instance.username = None
51+
cls.__instance.session_id = None
52+
cls.__instance.name = None
53+
cls.__instance.email = None
54+
55+
return cls.__instance
56+
57+
def set_username(self, username):
58+
self.username = username
59+
60+
def set_session_id(self, session_id):
61+
self.session_id = session_id
62+
63+
def set_name(self, name):
64+
self.name = name
65+
66+
def set_email(self, email):
67+
self.email = email
68+
69+
def get_username(self):
70+
return self.username
71+
72+
def get_session_id(self):
73+
return self.session_id
74+
75+
def get_name(self):
76+
return self.name
77+
78+
def get_email(self):
79+
return self.email
80+
81+
def end_session(self):
82+
self.username = None
83+
self.session_id = None
84+
self.name = None
85+
self.email = None
86+
Session.__instance = None
87+
88+
print("Sesión finalizada, con éxito...")
89+
90+
session1 = Session()
91+
session2 = Session()
92+
93+
session1.set_name('Manu')
94+
session1.set_session_id(1)
95+
session1.set_username("mrodara")
96+
session1.set_email("[email protected]")
97+
98+
print(session2.get_name())
99+
print(session2.get_username())
100+
print(session2.get_session_id())
101+
print(session2.get_email())
102+
103+
session2.end_session()
104+
105+
print(session1.get_name())
106+
print(session1.get_username())
107+
print(session1.get_session_id())
108+
print(session1.get_email())
109+
110+
### FIN EJERCICIO EXTRA
111+
112+
#### FIN PATRONES DE DISEÑO: SINGLETON
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#### PATRONES DE DISEÑO: DECORADORES
2+
3+
'''
4+
El Patrón Decorador es un patrón estructural que permite añadir funcionalidades a un objeto dinámicamente sin modificar su estructura original.
5+
Es especialmente útil cuando necesitas extender las capacidades de una clase de manera flexible y reutilizable.
6+
7+
En Python, este concepto también está integrado en el lenguaje a través de la sintaxis de decoradores,
8+
que simplifica el uso del patrón.
9+
'''
10+
11+
# Ejemplo básico con una función decoradora
12+
def decorador(funcion):
13+
def wrapper(*args, **kwargs):
14+
print("Antes de ejecutar la función")
15+
result = funcion(*args, **kwargs)
16+
print("Después de ejecutar la función")
17+
18+
return result
19+
20+
return wrapper
21+
22+
@decorador
23+
def saludo(name):
24+
print(f'Hola {name}, estás siendo saludado desde un decorador')
25+
26+
saludo("Manuel")
27+
28+
# En lugar de funciones también se pueden usar decoradores con Clases
29+
class DecoradorClase():
30+
def __init__(self, function):
31+
self.function = function
32+
33+
def __call__(self, *args, **kwargs):
34+
print("Antes de ejecutar la función")
35+
result = self.function(*args, **kwargs)
36+
print("Después de ejecutar la función")
37+
38+
return result
39+
40+
@DecoradorClase
41+
def saludo(name: str):
42+
print(f'Hola {name}, ahora el decorador es de clase')
43+
44+
saludo("Otra vez Manuel")
45+
46+
### EJERCICIO EXTRA
47+
class DecoradorContador():
48+
49+
count = 0
50+
51+
def __init__(self, function):
52+
self.function = function
53+
54+
def __call__(self, *args, **kwds):
55+
result = self.function(*args, **kwds)
56+
self.count += 1
57+
print(f'La función se ha ejecutado {self.count} veces')
58+
return result
59+
60+
@DecoradorContador
61+
def saludo(name: str):
62+
print(f'Hola {name}')
63+
64+
names = ['Antonio', 'Rita', 'Gabriel']
65+
66+
for name in names:
67+
saludo(name)
68+
69+
70+
### FIN EJERCICIO EXTRA
71+
#### FIN PATRONES DE DISEÑO: DECORADORES

0 commit comments

Comments
 (0)