Restructure content and add notes from HolaMundo

Signed-off-by: Manuel Vergara <manuel@vergaracarmona.es>
This commit is contained in:
2023-05-20 09:36:26 +02:00
parent 64ed03f811
commit f4e9797c4b
430 changed files with 889 additions and 24 deletions

View File

@@ -0,0 +1,2 @@
def saludar():
print('Hola, estoy en el modulo ocupado')

View File

@@ -0,0 +1,3 @@
from moduloOcupado import saludar
saludar()

View File

@@ -0,0 +1,10 @@
from paquete_ma import suma_y_resta
from paquete_ma.subpaquete_ma import saludo
# Importado del paquete
suma_y_resta.suma(1, 5)
suma_y_resta.resta(15, 3)
# Importado del subpaquete
saludo.hola()

View File

@@ -0,0 +1,2 @@
def hola():
print('hey!!')

View File

@@ -0,0 +1,6 @@
def suma(num1, num2):
print(num1 + num2)
def resta(num1, num2):
print(num1 - num2)

View File

@@ -0,0 +1,53 @@
"""
Manejo de errores
Intentar --> try
Excepción --> except
Finalmente --> finally
"""
def suma():
n1 = int(input('El numero 1: '))
n2 = int(input('El numero 2: '))
print(n1 + n2)
print('Gracias por sumar' + n1)
try:
# Codigo que queremos probar
suma()
except TypeError:
# Código a ejecutar si hay un error
print('Estas intentando concatenar tipos distintos')
except ValueError:
# Código a ejecutar si hay un error
print('Estas intentando sumar algo que no son números?')
else:
# Código a ejecutar si no hay un error
print('Hiciste todo bien')
finally:
# Código que se va a ejecutar de todos modos
print('Eso fue todo')
# Ejemplo para pedir un número de manera correcta
def pedir_numero():
while True:
try:
numero = int(input('Dame un número: '))
except:
print('\nEse no es un número')
else:
print(f'Ingresaste el número {numero}')
break
print('Gracias')
pedir_numero()

View File

@@ -0,0 +1,15 @@
"""
Probando pylint
"""
def una_funcion():
"""Funcion con variable que retorna un número."""
numero1 = 500
return numero1
RESULTADO = una_funcion()
# Imprimimos la variable
print(RESULTADO)

View File

@@ -0,0 +1,41 @@
"""
Numeros para práctica
"""
def numeros_perfumeria():
"""Esto es un comentario"""
for numeros_perfum in range(1, 10000):
yield f"P - {numeros_perfum}"
def numeros_farmacia():
"""Esto es un comentario"""
for numeros_farma in range(1, 10000):
yield f"F - {numeros_farma}"
def numeros_cosmetica():
"""Esto es un comentario"""
for numeros_cosmetic in range(1, 10000):
yield f"C - {numeros_cosmetic}"
p = numeros_perfumeria()
f = numeros_farmacia()
c = numeros_cosmetica()
def decorador(rubro):
"""Esto es un comentario"""
print("\n" + "*" * 23)
print("Su número es:")
if rubro == "P":
print(next(p))
elif rubro == "F":
print(next(f))
else:
print(next(c))
print("Aguarde y será atendido")
print("*" * 23 + "\n")

View File

@@ -0,0 +1,12 @@
"""
Esto es un comentario
"""
def sumar(numero1, numero2):
""" Comentando tal y tal """
return numero1+numero2
SUMA = sumar(5, 7)
print(SUMA)

View File

@@ -0,0 +1,2 @@
def todo_mayuscula(texto):
return texto.upper()

View File

@@ -0,0 +1,14 @@
import unittest
import cambia_texto
class ProbarCambiaTexto(unittest.TestCase):
def test_mayusculas(self):
palabra = 'buen dia'
resultado = cambia_texto.todo_mayuscula(palabra)
self.assertEqual(resultado, 'BUEN DIA')
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,70 @@
"""
Decoradores
Empiezan con @
Son funciones que modifican funciones.
"""
def cambiar_letras(tipo):
"""
Esto sirve para explicar
una función dentro de otra
"""
def mayusculas(text):
print(text.upper())
def minusculas(text):
print(text.lower())
if tipo == "may":
return mayusculas
elif tipo == "min":
return minusculas
operacion = cambiar_letras('may')
operacion('probando')
# Ahora vamos a crear un decorador
def decorar_saludo(funcion):
""" Una función con funciones dentro """
def otra_funcion(palabra):
print('Hola')
funcion(palabra)
print('adios')
return otra_funcion
# Ahora vamos a crear dos funciones
# una decorada y la otra no
@decorar_saludo
def trabajando(lugar):
print(f'Estoy trabajando en {lugar}....')
def durmiendo(lugar):
print(f'Estoy durmiendo en {lugar}')
trabajando("Python")
durmiendo('la cama')
print()
# Ahora vamos a usar el decorador
# directamente en una variable
durmiendo_decorado = decorar_saludo(durmiendo)
durmiendo_decorado('en la playa')

View File

@@ -0,0 +1,113 @@
"""
Funciones generadoras
se iteran pero espera a ejecutar al momento que se le pide
Utiliza yield (Construir) para retornar
y devuelve con next
"""
def mi_funcion():
for x in range(1, 5):
yield x * 10
def mi_generador():
for i in range(1, 4):
yield i
h = mi_funcion()
print(next(h))
g = mi_generador()
print(next(g))
print(next(g))
print(next(g))
print()
# Otro ejemplo
def mi_generation():
x = 1
yield x
x += 1
yield x
x += 1
yield x
i = mi_generation()
print(next(i))
print(next(i))
print(next(i))
print()
# Ejercicio 1
def infinito():
i = 0
while i != -1:
i += 1
yield i
generador = infinito()
print(next(generador))
print(next(generador))
print(next(generador))
print(next(generador))
print()
# Ejercicio 2
def infinito_siete():
i = 0
resultado = 7
while i != -1:
i += 1
resultado = 7 * i
yield resultado
generador = infinito_siete()
print(next(generador))
print(next(generador))
print(next(generador))
print(next(generador))
print()
# Ejercicio 2
def vidas():
yield "Te quedan 3 vidas"
yield "Te quedan 2 vidas"
yield "Te queda 1 vida"
yield "Game Over"
vida = vidas()
print(next(vida))
print(next(vida))
print(next(vida))
print(next(vida))

View File

@@ -0,0 +1,71 @@
"""
Programa día 8 - Turnero
Generadores y decorador
"""
def perfumeria():
""" Turnos de perfumeria """
turno_p = -1
while True:
turno_p += 1
yield f'P-{turno_p}'
def farmacia():
""" Turnos de farmacia """
turno_f = -1
while True:
turno_f += 1
yield f'F-{turno_f}'
def cosmetica():
""" Turnos de cosmetica """
turno_c = -1
while True:
turno_c += 1
yield f'C-{turno_c}'
def turnos(dpto):
"""Turnos perfumeria"""
print('Su turno es ')
if dpto == 'perfumeria':
print(next(perf))
elif dpto == 'farmacia':
print(next(farm))
elif dpto == 'cosmetica':
print(next(cos))
else:
print('Error')
print('Aguarde y será atendido')
# Variables
perf = perfumeria()
farm = farmacia()
cos = cosmetica()
turnos('perfumeria')
turnos('farmacia')
turnos('cosmetica')

View File

@@ -0,0 +1,77 @@
"""
Programa día 8 - Turnero
import numeros y funciones
"""
import os
import numeros
def clear_console():
""" Función limpiar consola """
limpiar = 'clear'
os.system(limpiar)
def bienvenida():
""" Bienvenida e inicio del programa """
clear_console()
# bienvenida al usuario
print(
'\n',
'#' * 40,
'\n # Bienvenid@ al turnero de farmacia #\n',
'#' * 40)
pausa()
clear_console()
nuevo_turno()
def pausa():
""" Pausar 3 segundos """
sleep = 'sleep 3'
os.system(sleep)
def nuevo_turno():
""" Expendedor de turnos """
comando = ""
while comando.lower() != 's':
clear_console()
print('¿De qué departamento quieres el turno?\n',
'\n DEPARTAMENTO\t| COMANDO',
'\n----------------|---------',
'\n Perfumería\t| [p]',
'\n Farmacia\t| [f]',
'\n Cosmética\t| [c]\n')
comando = input("> ")
if comando.lower() == 'p':
numeros.turnos('perfumeria')
elif comando.lower() == 'f':
numeros.turnos('farmacia')
elif comando.lower() == 'c':
numeros.turnos('cosmetica')
elif comando.lower() == 's':
print('Gracias por usar el turnero')
break
else:
print('Inserta un valor válido')
pausa()
bienvenida()

View File

@@ -0,0 +1,227 @@
# Día 8 - Programa una consola de turnos
## Índice
- [Día 8 - Programa una consola de turnos](#día-8---programa-una-consola-de-turnos)
- [Índice](#índice)
- [8.1. - Instalar paquetes](#81---instalar-paquetes)
- [8.2. - Módulos y paquetes](#82---módulos-y-paquetes)
- [8.3. - Manejo de errores](#83---manejo-de-errores)
- [8.4. - pylint](#84---pylint)
- [8.5. - unittest](#85---unittest)
- [8.6. - Decoradores](#86---decoradores)
- [8.7. - Generadores](#87---generadores)
- [8.8. - Proyecto del Día 8](#88---proyecto-del-día-8)
- [Ficheros y documentación](#ficheros-y-documentación)
## 8.1. - Instalar paquetes
Una de las grandes ventajas de Python como lenguaje de programación, es que cuenta con un amplia comunidad activa, que desarrolla paquetes que añaden muchas más funcionalidades.
PyPi (Python Package Index) es el repositorio de referencia para hallar paquetes desarrollados por la comunidad. https://pypi.org/
Si ya conoces el nombre del módulo que quieres instalar, puedes obtenerlo de PyPi directamente desde la consola:
```shell
pip install <modulo>
```
También podrás actualizar los módulos que ya tengas instalados añadiendo --upgrade luego del nombre del paquete:
```shell
pip install <modulo> --upgrade
```
No dejes de utilizar Google para investigar nuevos paquetes y sus funcionalidades.
## 8.2. - Módulos y paquetes
Los módulos no son más que archivos .py, que almacenan funciones, variables y clases, y pueden ser importado por otros. Los paquetes agrupan estos módulos en carpetas, de los cuales uno debe ser `__init__.py`
Importar un módulo:
```python
import modulo1
```
Importar una función del módulo:
```python
from modulo1 import funcion
```
Ejecutar desde la consola
```shell
C:\... ruta> python modulo1.py
```
Importar un módulo de un (sub) paquete
```python
from paquete.subpaquete import modulo3
```
Todos los paquetes, para ser considerados como tales, deben contar con un archivo __init__.py (constructor)
![](../img/dia08_01.png)
## 8.3. - Manejo de errores
Existen estrategias para capturar y gestionar los errores que pueden presentarse al ejecutar un programa, a fines de evitar una falla mayor y controlar la información que es mostrada al usuario.
```python
try:
```
El código que se encuentra dentro de try se ejecuta hasta finalizar o hasta que se presenta un error (excepción)
```python
except:
```
Contiene el manejador de errores (respuesta del programa ante un error), atrapando las excepciones que se presentan durante la ejecución de try*
```python
else:
```
Engloba el código que se ejecutará únicamente cuando ninguna excepción haya sido detectada en la ejecución de try (sin errores)
```python
finally:
```
Contiene código que se ejecuta siempre, se hayan presentado o no errores. *
![](../img/dia08_01.png)
Es buena práctica capturar y manejar las excepciones posibles individualmente y brindar información acerca del error y su possible solución.
```python
except ValueError:
except TypeError:
except FileNotFoundError:
...
```
Documentación python de errores: https://docs.python.org/es/3/library/exceptions.html
## 8.4. - pylint
Pylint es un verificador de código, errores y calidad para Python, siguiendo el estilo recomendado por PEP 8, la guía de estilo de Python. Es de gran utilidad en el trabajo en equipo.
```shell
pip install pylint
```
Ejecutar desde la consola:
```shell
ruta> pylint modulo1.py -r y
```
archivo de Python a evaluar
Al ejecutarse, Pylint devuelve un reporte con las características que fueron evaluadas, errores y puntuaciones parciales
```shell
Your code has been rated at 6.67/10
```
A mayor puntaje, mayor será la calidad de tu código. Un umbral aceptable será >= 7.00/10
## 8.5. - unittest
Unit Testing es un método o herramienta utilizado en programación para determinar si un módulo o un conjunto de módulos de código funciona correctamente. Dicha evaluación se realiza en un archivo independiente. En Python, se implementa desde el módulo incorporado unittest.
```python
import unittest
import mimodulo
class NombrePrueba(unittest.TestCase):
def test_prueba(self):
primer_valor = {algo}
segundo_valor = {salida de mimodulo.funcion}
self.assertEqual(primer_valor, segundo_valor, mensaje)
if __name__ == '__main__':
unittest.main()
```
Los primeros dos argumentos de assertEqual son dos valores que se comparan para establecer si hay igualdad entre ellos. Por eso, uno debe obtenerse a partir de una función del módulo evaluado, y otro ser la salida esperada para una misma entrada de información que en el primer caso. El tercer parámetro (mensaje), contendrá un string con información que se mostrará al usuario en caso de que el test falle.
Antes incluso de ejecutar el código, Python lee el archivo para definir algunas variables globales. Una de ellas es `__name__`, que toma el nombre "`__main__`" en caso que Python esté corriendo en dicho módulo de manera individual. Si por el contrario, el módulo fuera importado, la variable `__name__` toma el nombre del módulo. Este bloque de código evalúa que la prueba se esté ejecutando directamente.
## 8.6. - Decoradores
Los decoradores son patrones de diseño en Python utilizados para dar nueva funcionalidad a objetos (funciones), modificando su comportamiento sin alterar su estructura: **son funciones que modifican funciones**.
Las funciones en Python soportan operaciones tales como ser asignadas a una variable, pasadas como argumento, y ser devueltas por otra función como resultado.
También, es posible definir funciones dentro de funciones, sin que estén disponibles fuera de la función dentro de la cual fueron definidas.
Los decoradores permiten que una función se modifique ante determinados escenarios, sin duplicar código.
```python
def mostrar_informacion(funcion): > Función como parámetro de una función
def interior(): > Definición de una función dentro de otra
print(f'Ejecutando la función {funcion.__name__}')
funcion()
print('Ejecución finalizada')
return interior > Función que devuelve otra función como resultado
def impresion():
print("Hola Mundo")
funcion_decorada = mostrar_informacion(impresion) # Se asigna una función a una variable
funcion_decorada() # Ejecución de función decorada
```
Ejecutando la función impresion
Hola Mundo
Ejecución finalizada> Funcionalidad extendida
## 8.7. - Generadores
Los generadores son tipos especiales de funciones que devuelven un iterador que no almacena su contenido completo en memoria, sino que "demora" la ejecución de una expresión hasta que su valor se solicita.
```python
def secuencia_infinita():
num = 0
while True:
yield num
num += 1
```
Dado que un ordenador no cuenta con memoria infinita, no podría generarse una secuencia de números sin límite sin la ayuda de un generador.
Lo mismo ocurre con datos que, sin ser infinitos, ocuparían demasiado espacio en memoria de almacenarse repentinamente.
```python
generador = secuencia_infinita()
print(next(generador))
print(next(generador))
print(next(generador))
```
0
1
2
## 8.8. - Proyecto del Día 8
El desafío de hoy, es que crees un software que funcione como el turnero de una farmacia.
En nuestro caso, vas a crear el tunero para una farmacia que tiene tres áreas de atención: perfumería, farmacia (que es donde venden los medicamentos), y cosméticos. Tu programa le tiene que preguntar al cliente a cuál de las áreas desea dirigirse, y le va a dar un número de turno según a qué área se dirija. Por ejemplo, si elige cosmética le va a dar el número C-54 (“C” de cosmética). Luego de eso, nos va a preguntar si queremos sacar otro turno. Esto, en realidad, es para simular si viene un nuevo cliente. Y repetirá todo el proceso.
Algunas cosas a tener en cuenta:
Los diferentes clientes van a ir sacando turnos para diferentes áreas (perfumería, farmacia, cosmética), en diferentes órdenes, por lo que el sistema debe llevar la cuenta de cuántos turnos ha dado para cada una de esas áreas, y producir el siguiente número de cada área a medida que se lo pida. ¿No te parece genial aprovechar la eficiencia de los generadores para poder hacer esto?
Por otro lado, el mensaje donde le comunicamos el número de espera al cliente, debería tener algo de texto adicional antes y después del número. Por ejemplo, “su turno es (-el número de turno con el del comienzo-)”, y luego algo así como “aguarde y será atendido”. Para que nuestro código no se repita, en vez de poner ese texto en cada una de las funciones que calculen los números, podemos aprovechar la flexibilidad de los decoradores para crear ese texto adicional una sola vez, y luego envolver a cualquiera de nuestras funciones con ese texto único.
Finalmente, deberías aprovechar que ahora ya sabes dividir tu programa en diferentes módulos, y entonces separar el código en dos partes: por un lado, un módulo que se puede llamar **números.py**, en el que vas a escribir todos los generadores y el decorador, y un segundo módulo que podemos llamar **principal.py**, donde vas a escribir las funciones que administran el funcionamiento del programa (como las instrucciones para elegir un área y para decidir si seguirá tomando nuevos turnos o si va a finalizar el programa). Recuerda que vas a necesitar importar el contenido de numeros.py dentro de principal.py para poder disponer de sus funciones.
## Ficheros y documentación
- [01_pruebas_modulos](01_pruebas_modulos/)
- [02_pruebas_paquete](02_pruebas_paquete/)
- [03_manejo_errores.py](03_manejo_errores.py)
- [04_probando_pylint.py](04_probando_pylint.py)
- [05_probando_pylint](05_probando_pylint/)
- [06_probando_unittest](06_probando_unittest/)
- [07_decoradores.py](07_decoradores.py)
- [08_generadores.py](08_generadores.py)
- [09_programa08](09_programa08/)
[Documentación del día](../doc_curso/08_consola_turnos/)
---
Enlaces a todos los días: [dia 1 - creador de nombres](../dia_01/README.md) / [dia 2 - calculador de comisiones](../dia_02/README.md) / [dia 3 - analizador de texto](../dia_03/README.md) / [dia 4 - juego "adivina el número"](../dia_04/README.md) / [dia 5 - juego "El ahorcado"](../dia_05/README.md) / [dia 6 - recetario](../dia_06/README.md) / [dia 7 - cuenta bancaria](../dia_07/README.md) / [dia 8 - consola de turnos](../dia_08/README.md) / [dia 9 - buscador de números de serie](../dia_09/README.md) / [dia 10 - juego "Invasión espacial"](../dia_10/README.md) / [dia 11 - web scraping](../dia_11/README.md) / [dia 12 - gestor de restaurantes](../dia_12/README.md) / [dia 13 - asistente de voz](../dia_13/README.md) / [dia 14 - controlador de asistencia](../dia_14/README.md) / [dia 15 - machine learning](../dia_15/README.md) / [dia 16 - aplicación web de tareas pendientes](../dia_16/README.md)