Herramientas de usuario

Herramientas del sitio


informatica:programacion:python:cursos:introduccion_programacion_python:ejemplos_practicos

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
informatica:programacion:python:cursos:introduccion_programacion_python:ejemplos_practicos [2023/04/27 09:56] – [Testing: Pruebas unitarias] tempwininformatica:programacion:python:cursos:introduccion_programacion_python:ejemplos_practicos [2023/04/28 11:47] (actual) – [JSON en Python] tempwin
Línea 420: Línea 420:
 </code> </code>
  
-==== Testing: Pruebas unitarias =====+===== Testing: Pruebas unitarias =====
  
 Usaremos el módulo [[https://docs.python.org/3/library/unittest.html|unittest]] para las pruebas unitarias en Python. Usaremos el módulo [[https://docs.python.org/3/library/unittest.html|unittest]] para las pruebas unitarias en Python.
 +
 +Los tests unitarios están pensados para probar módulos aislados.
  
 Partimos de un programa: Partimos de un programa:
Línea 431: Línea 433:
  
 # Cálculo de las raíces # Cálculo de las raíces
-def segundo_grado(a, b, c):+def segundo_grado(a: float, b: float, c: float-> tuple: 
 + 
 +    """ 
 +    Calcula las soluciones reales de una ecuación de segundo grado. 
 +    Devuelve una tupla con las 2 soluciones reales o lanza una excepción  
 +    en caso de no tenerlas. 
 +    """
  
     d = b ** 2 - 4 * a *c     d = b ** 2 - 4 * a *c
Línea 489: Línea 497:
         self.assertAlmostEqual(segundo_grado(2, 4, -6), (1, -3))         self.assertAlmostEqual(segundo_grado(2, 4, -6), (1, -3))
  
 +    def test_ecuacion7(self):
 +        self.assertAlmostEqual(segundo_grado(1, -1, -1), (1.618033988749895, -0.6180339887498949))
 +
 +    def test_ecuacion8(self):
 +        
 if __name__ == '__main__': if __name__ == '__main__':
     unittest.main()             unittest.main()        
 </code> </code>
 +
 +Si hacemos modificaciones en el código, los tests nos aseguran que todo siga funcionando correctamente o que el cambio que hemos hecho hace que no pasen los test. De esa manera, podremos detectar si algo hemos hecho mal.
 +
 +Además, al hacer tests, estamos dejando por escrito las pruebas que realizaremos en nuestro código.
 +
 +Para lanzar la batería de tests desde la línea de comandos:
 +
 +<code>
 +python -m unittest test_segundo_grado.py
 +</code>
 +
 +==== Conversión a números romanos ====
 +
 +Esta vez crearemos primero los tests y luego crearemos el código :
 +
 +<WRAP center round info 60%>
 +**TDD** (//Test Driven Development//): técnica de desarrollo en la que primero se define el test y luego el código que debe satisfacer el test.
 +</WRAP>
 +
 +
 +Fichero ''test_romanos.py'':
 +
 +<code python>
 +import unittest
 +
 +from romanos import roman
 +
 +class TestRomanos(unittest.TestCase):
 +
 +    def test_1(self):
 +        self.assertEqual(roman(1), "I")
 +        
 +    def test_2(self):
 +        self.assertEqual(roman(2), "II")
 +        
 +    def test_2(self):
 +        self.assertEqual(roman(2), "II")
 +        
 +    def test_3(self):
 +        self.assertEqual(roman(3), "III")
 +        
 +    def test_4(self):
 +        self.assertEqual(roman(4), "IV")
 +        
 +    def test_5(self):
 +        self.assertEqual(roman(5), "V")
 +
 +    def test_6(self):
 +        self.assertEqual(roman(6), "VI")
 +        
 +    def test_7(self):
 +        self.assertEqual(roman(7), "VII")
 +
 +    def test_9(self):
 +        self.assertEqual(roman(9), "IX")
 +        
 +    def test_10(self):
 +        self.assertEqual(roman(10), "X")
 +
 +    def test_13(self):
 +        self.assertEqual(roman(13), "XIII")
 +        
 +    def test_14(self):
 +        self.assertEqual(roman(14), "XIV")
 +        
 +    def test_17(self):
 +        self.assertEqual(roman(17), "XVII")
 +        
 +    def test_19(self):
 +        self.assertEqual(roman(19), "XIX")
 +        
 +    def test_20(self):
 +        self.assertEqual(roman(20), "XX")
 +        
 +    def test_27(self):
 +        self.assertEqual(roman(27), "XVII")
 +
 +    def test_33(self):
 +        self.assertEqual(roman(33), "XXXIII")
 +        
 +    def test_40(self):
 +        self.assertEqual(roman(40), "XL")
 +
 +    def test_49(self):
 +        self.assertEqual(roman(49), "XLIX")
 +
 +    def test_50(self):
 +        self.assertEqual(roman(50), "L")
 +
 +    def test_62(self):
 +        self.assertEqual(roman(62), "LXII")
 +        
 +    def test_90(self):
 +        self.assertEqual(roman(90), "XC")
 +        
 +    def test_97(self):
 +        self.assertEqual(roman(90), "XCVII")
 +        
 +    def test_100(self):
 +        self.assertEqual(roman(100), "C")
 +
 +    def test_333(self):
 +        self.assertEqual(roman(333), "CCCXXXIII")
 +        
 +    def test_400(self):
 +        self.assertEqual(roman(400), "CD")
 +        
 +    def test_500(self):
 +        self.assertEqual(roman(500), "D")
 +        
 +    def test_666(self):
 +        self.assertEqual(roman(666), "DCLXVI")
 +        
 +    def test_900(self):
 +        self.assertEqual(roman(900), "CM")
 +        
 +    def test_1000(self):
 +        self.assertEqual(roman(1000), "M")
 +        
 +    def test_1666(self):
 +        self.assertEqual(roman(1666), "MDCLXVI")
 +        
 +    def test_3999(self):
 +        self.assertEqual(roman(3999), "MMMCMXCIX")
 +
 +if __name__ == '__main__':
 +    unittest.main()
 +
 +</code>
 +
 +Creamos el programa ''romanos.py'':
 +
 +<code python>
 +"""
 +Romani ite domum!
 +
 +TDD - Test Driven Development
 +
 +1. Escribir un test (que inicialmente falle)
 +2. Escribir el código que haga pasar el test
 +3. Refactorizar el código: optimización, limpieza, etc
 +(Y vuelta a empezar...)
 +"""
 +
 +def roman(n: int) -> str:
 +
 +    cantidades = [
 +        (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), 
 +        (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), 
 +        (5, "V"), (4, "IV"), (1, "I")
 +    ]
 +
 +    conv = ""
 +    
 +    for cant, letras in cantidades:
 +        while n >= cant.
 +            n -= cant
 +            conv += letras
 +    
 +    return conv
 +</code>
 +
 +Opción con recursividad:
 +
 +<code python>
 +def roman2(n: int) -> str:
 +
 +    if n >= 1000:
 +        return "M" + roman2(n - 1000)
 +    elif n >= 900:
 +        return "CM" + roman2(n - 900)
 +    elif n >= 500:
 +        return "D" + roman2(n - 500)    
 +    elif n >= 400:
 +        return "CD" + roman2(n - 400)    
 +    elif n >= 100:
 +        return "C" + roman2(n - 100)            
 +    elif n >= 90:
 +        return "XC" + roman2(n - 90)            
 +    elif n >= 50:
 +        return "L" + roman2(n - 50)            
 +    elif n >= 40:
 +        return "XL" + roman2(n - 40)            
 +    elif n >= 10:
 +        return "XL" + roman2(n - 10)            
 +    elif n >= 9:
 +        return "XL" + roman2(n - 9)            
 +    elif n >= 5:
 +        return "V" + roman2(n - 5)            
 +    elif n >= 4:
 +        return "IV" + roman2(n - 4)            
 +    elif n >= 1:
 +        return "I" + roman2(n - 1)                    
 +    else:
 +        return ""
 +</code>
 +
 +  * [[https://codewars.com|codewars]]: retos de programación
 +
 +===== JSON =====
 +
 +JSON (//JavaScript Object Notation//) formato para el intercambio de información.
 +
 +JSON no son más que objetos (que son equivalentes a los diccionarios de Python) y listas.
 +
 +Se trata de texto.
 +
 +  * https://www.json.org/json-en.html
 +
 +==== JSON en Python ====
 +
 +Aspecto de un JSON, que lo representamos como string:
 +
 +<code python>
 +datos_json = '''
 +{
 +    "glossary": {
 +        "title": "example glossary",
 +        "GlossDiv": {
 +            "title": "S",
 +            "GlossList": {
 +                "GlossEntry": {
 +                    "ID": "SGML",
 +                    "SortAs": "SGML",
 +                    "GlossTerm": "Standard Generalized Markup Language",
 +                    "Acronym": "SGML",
 +                    "Abbrev": "ISO 8879:1986",
 +                    "GlossDef": {
 +                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
 +                        "GlossSeeAlso": [
 +                            "GML",
 +                            "XML"
 +                        ]
 +                    },
 +                    "GlossSee": "markup"
 +                }
 +            }
 +        }
 +    }
 +}
 +'''
 +</code>
 +
 +  * [[https://docs.python.org/3/library/json.html|Tratamiento de JSON en Python (documentación oficial)]]
 +
 +<code python>
 +# Biblioteca de Python para el tratamiento de JSON
 +import json
 +
 +# Cargamos a partir de un string un objeto JSON/diccionario
 +datos = json.loads(datos_json)
 +
 +type(datos) # dict
 +
 +datos.keys() # dict_keys(['glossary'])
 +
 +glossary = datos['glossary'] # dict
 +
 +glossary.keys() # dict_keys(['title', 'GlossDiv'])
 +
 +paises_capitales = {
 +    "España": "Madrid",
 +    "Portugal": "Lisboa",
 +    "Italia": "Roma",
 +    "Francia": "Paris",
 +    "Alemania": "Berlin"
 +}
 +
 +type(paises_capitales) # dict
 +
 +# Si queremos pasar de un diccionario a string en formato JSON
 +json.dumps(paises_capitales)
 +</code>
 +
 +  * [[https://jsonviewer.stack.hu/|Online JSON Viewer]]
 +
 +Si procesamos un JSON inválido:
 +
 +<code python>
 +mal_json = '''
 +{"mal": "json"
 +'''
 +
 +try:
 +    json.loads(mal_json)
 +except json.JSONDecodeError as error:
 +    print("Error cargando JSON")
 +</code>
 +
 +
 +disculpa, Jairo, sabes hasta qué día tenemos disponible el acceso al campus virtual?
informatica/programacion/python/cursos/introduccion_programacion_python/ejemplos_practicos.1682582168.txt.gz · Última modificación: por tempwin