{ "cells": [ { "cell_type": "markdown", "id": "9cc65481-e4c1-4286-9a2c-ce49c3f071a6", "metadata": {}, "source": [ "# B: Más python: Funciones, módulos y paquetes, clases...\n", "\n", "## Funciones\n", "\n", "A veces programaremos una funcionalidad que queremos reutilizar en varios sitios de nuestro programa (para evitar repetir código). Esto lo podemos hacer con las llamadas **funciones**:" ] }, { "cell_type": "code", "execution_count": 1, "id": "6de496de-85b1-4d4d-9045-f5e7b17440cd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Esto es un texto muy interesante\n", "Que va a ser impreso varias veces en mi programa\n", "Por eso creo una función para no repetir las mismas sentencias varias veces\n", "\n", "Esto es un texto muy interesante\n", "Que va a ser impreso varias veces en mi programa\n", "Por eso creo una función para no repetir las mismas sentencias varias veces\n", "\n", "Esto es un texto muy interesante\n", "Que va a ser impreso varias veces en mi programa\n", "Por eso creo una función para no repetir las mismas sentencias varias veces\n", "\n" ] } ], "source": [ "def imprimeTexto():\n", " print(\"Esto es un texto muy interesante\")\n", " print(\"Que va a ser impreso varias veces en mi programa\")\n", " print(\"Por eso creo una función para no repetir las mismas sentencias varias veces\\n\")\n", " \n", "imprimeTexto()\n", "imprimeTexto()\n", "imprimeTexto()" ] }, { "cell_type": "markdown", "id": "3cfd93f1-91fe-4f19-9cd7-3b95c424f5ee", "metadata": {}, "source": [ "+ ```def``` es una palabra reservada que indica que estamos definiendo una función.\n", "+ ```imprimeTexto``` es el nombre que le damos a nuestra nueva función.\n", "+ ```()``` permite especificar parámetros que tendrá nuestra función (en nuestro caso ninguno)\n", "+ ```:``` delimita el comienzo del bloque de instrucciones que formará la función." ] }, { "cell_type": "markdown", "id": "d2e8b499-9a1d-4adb-b0a0-96aa6d49b32b", "metadata": {}, "source": [ "### Parámetros (argumentos) en las funciones\n", "\n", "En nuestro caso no hemos utilizado ningún **parámetro** en la función, pero usualmente podemos definir parámetros para condicionar la ejecución de la función. Los parámetros de una función se especifican en la definición de la misma entre los paréntesis de después del nombre de la función y serparados por comas si hay más de uno.\n", "\n", "Asímismo las funciones pueden devolver un valor resultado de ejecutar dicha función con la instrucción ```return```." ] }, { "cell_type": "code", "execution_count": 2, "id": "be337f2f-9280-4023-94c9-f6e05624acd4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n" ] } ], "source": [ "def esPar(numero):\n", " return numero % 2 == 0\n", "\n", "print(esPar(7))\n", "\n", "print(esPar(10))" ] }, { "cell_type": "markdown", "id": "584749e6-bf05-4b52-994b-e4e71db454c0", "metadata": {}, "source": [ "Otro ejemplo:" ] }, { "cell_type": "code", "execution_count": 3, "id": "eddc8dff-9882-42b9-b9ff-3ad2c5e39481", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "def esPrimo(numero):\n", " for n in range(2, numero):\n", " if (numero % n == 0):\n", " return False\n", " \n", " return True\n", " \n", "print(esPrimo(29))\n", "\n", "print(esPrimo(42))" ] }, { "cell_type": "markdown", "id": "d9ac05f2-8004-4c04-a165-f74510e405c7", "metadata": {}, "source": [ "### Ámbito de las variables (scope)\n", "\n", "Las variables definidas dentro de una función tienen *ámbito local*, es decir, solo pueden ser accedidas desde dentro de esa misma función. Dejan de tener valor una vez que la función finaliza su ejecución:" ] }, { "cell_type": "code", "execution_count": 4, "id": "48b44875-2bc1-4ecd-a4be-8286df944b3b", "metadata": {}, "outputs": [], "source": [ "def miFuncion():\n", " contador = 10\n", " \n", " return contador\n", "\n", "# print(contador) # Dará NameError, porque no podemos acceder a la variable local desde fuera" ] }, { "cell_type": "markdown", "id": "3b395487-648b-4358-bb04-8ec05e43af4d", "metadata": {}, "source": [ "Las variables declaradas *fuera* de cualquier función tienen *ámbito global* y puede ser leida desde cualquier función (o incluso otros módulos que veremos más adelante):" ] }, { "cell_type": "code", "execution_count": 5, "id": "09aca9e2-fbb2-4afe-afa3-cd6a27887914", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7\n" ] } ], "source": [ "contador = 7\n", "\n", "def miFuncion():\n", " print(contador)\n", " \n", "miFuncion()" ] }, { "cell_type": "markdown", "id": "3f180967-3133-4d28-bec3-eeb392bd6edb", "metadata": {}, "source": [ "En este caso SÍ podemos acceder a la variable ```contador``` desde una función porque tiene *ámbito global*. Para modificar una variable global desde una función hay que usar la palabra reservada ```global```. Si no, al asignar el valor dentro de la función se creará una variable *local* con el mismo nombre (pero distinta):" ] }, { "cell_type": "code", "execution_count": 6, "id": "9e381859-c3ac-4713-b595-ed4b6c3ed817", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Valor inical de contador: 7\n", "Desde dentro de miFuncion1 contador vale 3\n", "La variable contador global no se ha modificado: 7\n", "Desde dentro de miFuncion2 contador vale 5\n", "Al usar dentro de la función global SI se modifica la varable global: 5\n" ] } ], "source": [ "contador = 7\n", "\n", "def miFuncion1():\n", " contador = 3\n", " \n", " print(f\"Desde dentro de miFuncion1 contador vale {contador}\")\n", " \n", "def miFuncion2():\n", " global contador\n", " \n", " contador = 5\n", " \n", " print(f\"Desde dentro de miFuncion2 contador vale {contador}\")\n", " \n", "print(f\"Valor inical de contador: {contador}\")\n", "\n", "miFuncion1()\n", "\n", "print(f\"La variable contador global no se ha modificado: {contador}\")\n", "\n", "miFuncion2()\n", "\n", "print(f\"Al usar dentro de la función global SI se modifica la varable global: {contador}\")" ] }, { "cell_type": "markdown", "id": "6c3363f9-1e6e-40b7-adce-05647cbc3bb4", "metadata": {}, "source": [ "Como norma general: Es MUY MALA PRÁCTICA usar variables globales dentro de las funciones. Puede parecer cómodo. Puede parecer práctico, pero en menos tiempo del que parece depurar ese código será un infierno. ¡Advertidos quedáis!" ] }, { "cell_type": "markdown", "id": "dd3bcb1e-9b73-41e5-92cb-afd690c3f418", "metadata": {}, "source": [ "***\n", "**Ejercicio B.7:**\n", "\n", "En el ejercicio B.1 calculamos el valor de una función polinómica de grado 2. Construyamos una función llamada ```polinomio``` que admita como parametros ```x```, ```a```, ```b``` y ```c``` y devuelva el resultado de la evaluación del polinomio." ] }, { "cell_type": "code", "execution_count": 7, "id": "e0ac4e42-e2de-4165-b54f-99aecfbe4965", "metadata": {}, "outputs": [], "source": [ "# Tu código aquí\n", " \n", "#polinomio(1, 2, 1, -2)" ] }, { "cell_type": "markdown", "id": "e068bb26-ab05-4b94-81fb-57c13949d642", "metadata": {}, "source": [ "***\n", "**Ejercicio B.8:**\n", " \n", "Hagamos una función ```evaluaPolinomio``` usando la función ```polinomio``` del ejercicio anterior devuelva una lista de tuplas $(x, f(x))$ evaluando el polinomio en diferentes $x$. Como parámetros debe admitir ```xMin```, ```xMax```, ```xStep``` (incremento de evaluación entre ```xMin``` y ```xMax```), ```a```, ```b``` y ```c```. Luego prueba las última líneas comentadas... ¡a ver que pasa!\n", "\n", "**Nota:** Para que funcione la última parte del ejercicio (que grafica el resultado) hace falta instalar un paquete de Python llamado ```matplotlib```. Para hacerlo abrimos un nuevo ```Anaconda prompt```, activamos el entorno ```cursoAstronomia``` y ejecutamos:\n", "\n", "```bash\n", "> conda install -c conda-forge matplotlib\n", "```\n", "\n", "Es posible que tengamos que reiniciar el Kernel de ```JupiterLab``` para que tenga efecto la instalación del nuevo paquete: ```Kernel``` $\\rightarrow$ ```Restart Kernel...```. En alguna rara ocasión p" ] }, { "cell_type": "code", "execution_count": 8, "id": "2a3311ec-9f7d-46af-ad44-035e8ddfc5bd", "metadata": {}, "outputs": [], "source": [ "#def evaluaPolinomio(xMin, xMax, xStep, a, b, c):\n", " \n", "# Tu código aquí\n", "\n", "#puntos = evaluaPolinomio(-1, 1, .1, 2, 1, -2)\n", "\n", "#import matplotlib.pyplot as plt # Esto aún no hay que entenderlo. Lo veremos más adelante.\n", "#x, y = zip(*puntos)\n", "#plt.plot(x, y)\n", "#plt.show()" ] }, { "cell_type": "markdown", "id": "78835464-e47d-4405-b3aa-d75b74ef9945", "metadata": {}, "source": [ "***\n", "### Parámetros con nombre (y valores por defecto)\n", "\n", "Se pueden pasar los argumentos de una función por nombre. Eso permite cambiar el orden de los parámetros y, además, ganaremos en legibilidad:" ] }, { "cell_type": "code", "execution_count": 9, "id": "40ec4391-a31e-4e72-aa45-039202d2dc82", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "30.05027777777778\n", "30.05027777777778\n", "30.05027777777778\n", "30.05027777777778\n" ] } ], "source": [ "def graMinSeg2Gra(grados, minutos, segundos):\n", " return grados + minutos / 60 + segundos / 60 ** 2\n", "\n", "print(graMinSeg2Gra(30, 3, 1))\n", "\n", "print(graMinSeg2Gra(grados = 30, minutos = 3, segundos = 1))\n", "\n", "print(graMinSeg2Gra(segundos = 1, grados = 30, minutos = 3))\n", "\n", "print(graMinSeg2Gra(30, 3, segundos = 1)) # Se puede mezclar por posición y por nombre, pero no es muy recomendable" ] }, { "cell_type": "markdown", "id": "bed5fb85-b0ca-4cae-a344-0ad21a1e26a8", "metadata": {}, "source": [ "Además, podemos dar valores por defecto a algunos parámetros de manera que no sea obligatorio especificarlos siempre:" ] }, { "cell_type": "code", "execution_count": 10, "id": "3103027c-fd0a-4fdb-95b5-70e6bb7fe936", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "30.05\n" ] } ], "source": [ "def graMinSeg2Gra(grados, minutos, segundos = 0.0): # No hará falta especificar los segundos\n", " return grados + minutos / 60 + segundos / 60 ** 2\n", "\n", "print(graMinSeg2Gra(30, 3)) # Esto fallaría con la función de antes" ] }, { "cell_type": "markdown", "id": "94e514e7-606e-4b83-a7d4-a6d4f86ec6ab", "metadata": {}, "source": [ "Además podemos tener funciones con un número de parámetros variable:" ] }, { "cell_type": "code", "execution_count": 11, "id": "d8aebab8-5ea1-4510-bfe9-7c50b91b5ae6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "21\n" ] } ], "source": [ "def sumaTodo(*valores): # Valores será una tupla con todos los parámetros que se le pasen a la función\n", " suma = 0\n", " \n", " for v in valores:\n", " suma = suma + v\n", " \n", " return suma\n", "\n", "print(sumaTodo(1,2,3,4,5,6))" ] }, { "cell_type": "markdown", "id": "a5ef02b6-8e5b-4330-9637-6dddf3faac20", "metadata": {}, "source": [ "[Más información al respeto (español)](https://interactivechaos.com/es/manual/tutorial-de-python/tipos-de-argumentos) - [Y otra página más (inglés)](https://treyhunner.com/2018/04/keyword-arguments-in-python/)" ] }, { "cell_type": "markdown", "id": "7cbc1a8f-39ea-4751-8394-f07814504349", "metadata": {}, "source": [ "***\n", "**Ejercicio B.9:**\n", "\n", "Hagamos una función similar a la del ejercicio B.7 llamada ```polinomioN```, pero que acepte un argumento ```x``` con valor por defecto 0.0 y un número indeterminado de argumentos que serían los coeficientes ```a```, ```b```, ```c``` del polinomio de grado igual al número de coeficientes menos uno (si te pasan 3 parámetros será un polinomio de grado 2)." ] }, { "cell_type": "code", "execution_count": 12, "id": "88fbd6e5-00ad-4368-9b86-cb98ed25d74e", "metadata": {}, "outputs": [], "source": [ "# Tu código aquí\n", "\n", "# polinomioN(3, 2, 1, -2, x=2.0)" ] }, { "cell_type": "markdown", "id": "c269823d-13c3-47ff-9f39-638097c1c011", "metadata": {}, "source": [ "***\n", "### Pasando funciones como parámetro\n", "\n", "Las funciones pueden a su ver pasarse como parámetros a otra función ([más información](https://es.stackoverflow.com/questions/139223/se-puede-pasar-una-funci%C3%B3n-como-par%C3%A1metro-en-python)):" ] }, { "cell_type": "code", "execution_count": 13, "id": "6c845b1d-bf2b-435f-9dcb-4073b3e95512", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9\n", "16\n", "25\n", "2.23606797749979\n", "2.449489742783178\n", "2.6457513110645907\n" ] } ], "source": [ "def cuadrado(x):\n", " return x ** 2\n", "\n", "def raiz_cuadrada(x):\n", " return x ** 0.5\n", "\n", "def operar(func, *args):\n", " for n in args:\n", " print(func(n))\n", " \n", "operar(cuadrado, 3, 4, 5)\n", "\n", "operar(raiz_cuadrada, 5, 6, 7)" ] }, { "cell_type": "markdown", "id": "43b0146a-f966-4912-9474-6a51d16709a9", "metadata": {}, "source": [ "***\n", "**Ejercicio B.10:**\n", "\n", "Creemos una función ```evaluaF``` similar a la del ejercicio B.8 que evalue en varios puntos (de ```xMin``` a ```xMax``` en pasos de ```xStep```). Pasaremos como parámetro una nueva función ```raizCubica``` y ```sierra``` que viene definida por $sierra(x) = x \\pmod 1$.\n", "\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "854f4d2f-4336-4914-ba77-f97f0fec9c1b", "metadata": {}, "outputs": [], "source": [ "# Tu código aquí\n", "\n", "#puntos1 = evaluaF(raizCubica)\n", "#puntos2 = evaluaF(sierra)\n", "\n", "#import matplotlib.pyplot as plt \n", "#x, y = zip(*puntos1)\n", "#plt.plot(x, y)\n", "#x, y = zip(*puntos2)\n", "#plt.plot(x, y)\n", "#plt.show()" ] }, { "cell_type": "markdown", "id": "0cc22aa5-f71d-4aa6-89ec-98502a3830cd", "metadata": {}, "source": [ "### Desempaquetado de tuplas (y otros iterables)\n", "\n", "Una característica interesante de Python es que es muy fácil y visual tener funciones que devuelvan más de un valor usando el *desempaquetado* ([Más información -se puede complicar mucho-](https://pharos.sh/unpacking-en-python-mas-alla-de-la-asignacion-paralela/)). Por ejemplo si queremos resolver la ecuación de segundo grado y que nos devuelva las 2 raices con la fórmula $x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$" ] }, { "cell_type": "code", "execution_count": 15, "id": "a0f8ac9e-9236-4235-8c52-25dbdb2e9109", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Las soluciones de la ecuación son: 8.0 y 2.0\n" ] } ], "source": [ "def segGrado(a, b, c):\n", " aux = (b**2 - 4*a*c) ** 0.5\n", " \n", " return ((-b + aux) / (2*a), (-b - aux) / (2*a))\n", "\n", "sol1, sol2 = segGrado(1, -10, 16)\n", "\n", "print(f\"Las soluciones de la ecuación son: {sol1} y {sol2}\")" ] }, { "cell_type": "markdown", "id": "870bbd73-6119-4b49-a3ed-fc65fcc14c2c", "metadata": {}, "source": [ "### Otras funciones interesantes\n", "\n", "```range(start, stop, step)```: Para iterar en una lista de números (en realidad no es una función ni una lista). [Más información](https://www.mclibre.org/consultar/python/lecciones/python-range.html)" ] }, { "cell_type": "code", "execution_count": 16, "id": "18171104-502f-49f1-80cc-42a20e6d78f6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "5\n", "7\n", "9\n", "11\n", "13\n", "15\n", "17\n" ] } ], "source": [ "for n in range(3, 19, 2):\n", " print(n)" ] }, { "cell_type": "markdown", "id": "e00f9ebc-9e35-4ed7-8e1d-3e11acf41060", "metadata": {}, "source": [ "```enumerate```: “Devuelve” una lista de tuplas con cada elemento y su posición en la lista (contador):" ] }, { "cell_type": "code", "execution_count": 17, "id": "2e1b2d6e-78a7-4460-8a55-0215bd5c05b2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0: Enero\n", "1: Febrero\n", "2: Marzo\n", "3: Abril\n", "4: Mayo\n", "5: Junio\n", "6: Julio\n", "7: Agosto\n", "8: Septiembre\n", "9: Octubre\n", "10: Noviembre\n", "11: Diciembre\n" ] } ], "source": [ "lista = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']\n", "\n", "for indice, valor in enumerate(lista): # Usamos el desempaquetado\n", " print(f\"{indice}: {valor}\")" ] }, { "cell_type": "markdown", "id": "357b911d-9a92-4765-a5b2-1a416f02cfb1", "metadata": {}, "source": [ "```round(x, d)```: Redondea ```x``` a ```d``` cifras decimales:" ] }, { "cell_type": "code", "execution_count": 18, "id": "94ce2af8-3fd2-4c98-ba44-b57eead92f56", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-17.73" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(-17.728384, 2)" ] }, { "cell_type": "markdown", "id": "4c4c91aa-9d5a-4fab-a35f-2160e5aa3fc5", "metadata": {}, "source": [ "### List comprehension (¿comprensión de listas?)\n", "\n", "Existe una manera compacta para operar sobre los elementos de una lista llamada *list comprehension*. [Más información al respecto (inglés)](https://www.programiz.com/python-programming/list-comprehension). A continuación unos ejemplos:" ] }, { "cell_type": "code", "execution_count": 19, "id": "4610d085-36ac-4986-a5ae-b2688091810a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" ] } ], "source": [ "# Inicializar una lista de 30 ceros:\n", "lista = [0 for x in range(30)]\n", "print(lista)" ] }, { "cell_type": "code", "execution_count": 20, "id": "d06bfb5f-745c-4f37-8160-872a6a86b056", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]\n" ] } ], "source": [ "# Iniciar una lista con valores de 0 a 29\n", "lista = [x for x in range(30)]\n", "print(lista)" ] }, { "cell_type": "code", "execution_count": 21, "id": "b9bf5a6c-ee2f-477a-ab7d-860e3bf20719", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]\n" ] } ], "source": [ "# Iniciar lista con valores pares menores que 30\n", "lista = [x for x in range(30) if x%2 == 0]\n", "print(lista)" ] }, { "cell_type": "code", "execution_count": 22, "id": "e7ab36ba-ca8c-4776-bb0b-ae3e8ce6cb53", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 8, 64, 216, 512, 1000, 1728, 2744, 4096, 5832, 8000, 10648, 13824, 17576, 21952]\n" ] } ], "source": [ "# Crear un lista con todos los valores de otra lista elevados al cubo\n", "lista2 = [x**3 for x in lista]\n", "print(lista2)" ] }, { "cell_type": "markdown", "id": "bb3078f7-99c8-429b-9b94-7ecb7603b99f", "metadata": {}, "source": [ "***\n", "**Ejercicio B.11:**\n", "\n", "Si quisieramos listar todos los números primos menores de un valor ```n``` utilizar la función anteriormente definida ```esPrimo()``` para cada valor posible sería bastante ineficiente. Vamos a implementar una función que haga la [criba de Eratóstenes](https://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes) que devuelva una lista de todos los primos menores de ```n```." ] }, { "cell_type": "code", "execution_count": 23, "id": "5754e1e6-14cc-4c3d-bed5-eda0b596d2fd", "metadata": {}, "outputs": [], "source": [ "#def cribaEratostenes(n):\n", "\n", "# Tu código aquí\n", "\n", "\n", "# print(cribaEratostenes(40))" ] }, { "cell_type": "markdown", "id": "8d99baf7-4ee4-48c2-bcc7-c139a0f7861c", "metadata": {}, "source": [ "## Módulos y Paquetes\n", "\n", "### Módulos\n", "\n", "Un módulo es un archivo de Python (típicamente con extensión ```.py```) cuyos objetos pueden accederse desde nuestro código. Sirven para organizar mejor grandes cantidades de código. Por ejemplo, tenemos el fichero ([funciones.py](./funciones.py)), donde se definen las funciones ```cuad(x)```, ```cubo(x)``` y ```raizN(x,n)```. Podemos usarlas de la siguiente manera:" ] }, { "cell_type": "code", "execution_count": 24, "id": "947d9b4b-8d95-4afb-a411-efd17cb861f4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9\n" ] } ], "source": [ "import funciones\n", "\n", "print(funciones.cuad(3))" ] }, { "cell_type": "markdown", "id": "5ccd618a-cae5-4e59-9bfc-18eb94727390", "metadata": {}, "source": [ "Cuidado porque ```JupyterLab``` no recarga los módulos aunque cambien. Si necesitas recargarlo porque has modificado el módulo tendrás que reiniciar el *Kernel* (```Kernel``` $\\rightarrow$ ```Restart Kernel```) o bien usar:" ] }, { "cell_type": "code", "execution_count": 25, "id": "5dcb4fa2-02b1-4126-966e-bcfad458785e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import importlib\n", "importlib.reload(funciones)" ] }, { "cell_type": "markdown", "id": "3e7c2127-6584-4404-9811-acdc4f59beed", "metadata": {}, "source": [ "Si no queremos escribir el nombre del módulo delante de las funciones podemos importarlas de la siguiente manera:" ] }, { "cell_type": "code", "execution_count": 26, "id": "991c3eaf-8b46-4bc4-927c-58d33f429183", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.0\n" ] } ], "source": [ "from funciones import cuad, raizN\n", "\n", "print(raizN(27, 3))" ] }, { "cell_type": "markdown", "id": "428f6fcb-45ef-445f-8192-9161c9dbf1d8", "metadata": {}, "source": [ "Y si las queremos todas (aunque habrá que tener cuidado de que no haya funciones con el mismo nombre importadas de distintos módulos):" ] }, { "cell_type": "code", "execution_count": 27, "id": "ad9cfd4d-ca05-4f4b-a452-e418d5c80026", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "125\n" ] } ], "source": [ "from funciones import *\n", "\n", "print(cubo(5))" ] }, { "cell_type": "markdown", "id": "92addc68-a27e-428e-9211-c23669d6f36f", "metadata": {}, "source": [ "### Paquetes\n", "\n", "Los paquetes son carpetas con múltiples módulos. [Más información al respecto](https://tutorial.recursospython.com/modulos-y-paquetes/)." ] }, { "cell_type": "markdown", "id": "063d2e4c-b94b-4301-8ddb-0642b69bf8c2", "metadata": {}, "source": [ "### Módulos y paquetes básicos de interés\n", "\n", "Python viene de serie con una colección grande de paquetes y módulos estándar (para matemáticas, números complejos, números \"aleatorios\" ([El azar es imposible](https://www.youtube.com/watch?v=RzEjqJHW-NU)), funciones estadísticas, manejo de ficheros...). Puedes consultar una lista de los mismos en la [documentación de la biblioteca estándar de Python](https://docs.python.org/es/3/library/index.html)." ] }, { "cell_type": "markdown", "id": "f3ba2569-7a36-428c-aa9a-5d16250f6261", "metadata": {}, "source": [ "#### Módulo ```math``` \n", "\n", "[Documentación](https://docs.python.org/es/3/library/math.html)\n", "\n", "Ejemplos:" ] }, { "cell_type": "code", "execution_count": 28, "id": "41846ae3-be6d-412d-bd17-1ae4254e072b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.72" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "\n", "math.fabs(-3.72) # Valor absoluto" ] }, { "cell_type": "code", "execution_count": 29, "id": "99189bca-3a3b-4d10-87d2-01e8e2ad18f5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.sqrt(9) # Raiz cuadrada" ] }, { "cell_type": "code", "execution_count": 30, "id": "c9873cfe-41f4-42a6-8e74-a52180a488f0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.302585092994046" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.log(10) # Logaritmo" ] }, { "cell_type": "code", "execution_count": 31, "id": "dad46966-87af-4b1e-a0f6-727b6c539621", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.log10(100) # Logaritmo base 10" ] }, { "cell_type": "code", "execution_count": 32, "id": "6ebf80db-2cf4-4441-9f23-e145ec1f3474", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6.123233995736766e-17" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.cos(math.pi / 2) # Coseno y la constante PI" ] }, { "cell_type": "code", "execution_count": 33, "id": "1f0042fe-cf13-4c25-b119-ac77725e516b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(math.cos(math.pi / 2), 1) # Menos feo" ] }, { "cell_type": "markdown", "id": "625c5ead-2f2e-4d93-b2dd-41f63bfe9d78", "metadata": {}, "source": [ "Un buen artículo (en inglés) que habla sobre algunas funciones de Python que puede resultar interesante conocer:\n", "\n", "[Python built-in functions to know](https://treyhunner.com/2019/05/python-builtins-worth-learning/)" ] }, { "cell_type": "markdown", "id": "6c239190-26ff-4c10-b96f-beac9e7b5c4a", "metadata": {}, "source": [ "## Programación Dirigida a Objetos (PDO): Clases, Propiedades, Métodos y Objetos\n", "\n", "La PDO es un paradigma de programación en el que la información y las operaciones que la manipulan se encapsulan en unas entidades denominadas objetos que pertenecen a determinadas clases. Veamos como lo implementa Python con ejemplos:" ] }, { "cell_type": "code", "execution_count": 34, "id": "cc8366e4-eb6a-4a51-a141-64fff5512429", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "777908924.0\n", "Mercurio\n" ] } ], "source": [ "class Planeta:\n", " \n", " nombre = \"\"\n", " diametro = 0.0\n", " distanciaSol = 0.0\n", " \n", " def __init__(self, nombre, diam, distSol):\n", " self.nombre = nombre\n", " self.diam = diam\n", " self.distanciaSol = distSol\n", " \n", " def getNombre(self):\n", " return nombre\n", " \n", " def getDistanciaSol(self):\n", " return self.distanciaSol\n", " \n", " def getDistanciaSolKm(self):\n", " return self.distanciaSol * 149597870\n", " \n", "\n", "jupiter = Planeta(\"Júpiter\", 192984, 5.2)\n", "mercurio = Planeta(\"Mercurio\", 4879, 0.39)\n", "\n", "print(jupiter.getDistanciaSolKm())\n", "print(mercurio.nombre)" ] }, { "cell_type": "markdown", "id": "aa283a0a-3dee-471a-8e9e-e3ba3a8226be", "metadata": {}, "source": [ "Hemos definido una clase llamada ```Planeta``` junto con unas pocas *propiedades* y métodos. Particularmente tenemos que:\n", "\n", "+ ```class``` es una palabra reservada para definir una *clase*\n", "+ ```Planeta``` es el nombre de la clase (para los nombres de las clases se suele usar [Upper CamelCase](https://es.wikipedia.org/wiki/Camel_case)\n", "+ ```nombre```, ```diametro``` y ```distanciaSol``` son las *propiedades* de la clase (las variables que contiene un objeto de esa clase)\n", "+ ```getNombre```, ```getDistanciaSol``` y ```getDistanciaSolKm``` son los *métodos* de la clase (las funciones que permiten operar con las ropiedades de la clase). Es muy *importante* fijarse en que el primer argumento de cualquier método es siempre ```self``` (el propio objeto).\n", "+ ```self.``` se us para acceder a cualquiera de los métodos o propiedades del objeto desde *dentro* del objeto (desde el código de sus propios métodos).\n", "+ ```__init__``` es un método especial llamado *constructor* que se ejecuta siempre que se instancie (cree) un objeto de dicha clase y sirve normalmente para iniciar las propiedades del objeto. Hay que fijarse que al ser un método como otro cualquiera su primer argumento es ```self```.\n", "\n", "En la línea\n", "\n", "```python\n", "jupiter = Planeta(\"Jupiter\", 192984, 5.2)\n", "```\n", "\n", "asignamos a una variable llamada ```jupiter``` un objeto de la clase ```Planeta```. Se ejecutará el constructor al que le pasamos una serie de parámetros. \n", "\n", "La sintaxis para ejecutar uno de los métodos del objeto o para acceder a sus propiedades se hace usando un ```.``` que separa el nombre de la variable y el método o propiedad al que queremos acceder:\n", "\n", "```python\n", " jupiter.getDistanciaAlSolKm() # Llamamos a un método del objeto que está\n", " # en la variable jupiter\n", " \n", " mercurio.nombre # Accedemos al valor de la propiedad nombre\n", " # del objeto que está en la variable mercurio\n", "```\n", "\n", "Sobre el paradigma de orientación a objetos hay mucho que se puede decir (herencia, polimorfismo, encapsulamiento...), pero dichos conceptos se salen del ámbito de este curso. Algunos enlaces más interesantes:\n", "+ [Más información sobre la PDO en Python](https://entrenamiento-python-basico.readthedocs.io/es/latest/leccion9/poo.html).\n", "+ [¡No temas a la POO!](http://sepwww.stanford.edu/data/media/public/sep/jon/family/jos/oop_es/oop1.htm): Un tutorial sobre programación orientada objetos contando una historia inspirada en el lejano oeste norte-americano. En principio pensado para programadores de `Java`, pero muchos conceptos como la [herencia](https://entrenamiento-python-basico.readthedocs.io/es/latest/leccion9/herencia.html) son perfectamente válidos en `Python`." ] }, { "cell_type": "markdown", "id": "96d658af-b355-4f44-a938-2bce893e7ce1", "metadata": {}, "source": [ "***\n", "**Ejercicio B.12:**\n", "\n", "Creemos una clase llamada ```Polinomio``` que nos permita encapsular la información de un polinomio de grado arbitrario ```n```. Dicha clase debe almacenar la información de sus coeficientes y debe proveer métodos para:\n", "\n", "+ obtener los coeficientes del polinomio, \n", "+ para obtener el coeficiente con índice ```n```, \n", "+ para obtener el grado del polinomio,\n", "+ para evaluar el polinomio en cualquier punto ```x``` y \n", "+ para obtener una lista de puntos evaluados similar a la del ejercicio B.8." ] }, { "cell_type": "code", "execution_count": 35, "id": "8e02bc9b-6720-4c9f-bd2b-1e94082d5550", "metadata": {}, "outputs": [], "source": [ "#class Polinomio:\n", " \n", "# Tu código aquí\n", "\n", "#pol1 = Polinomio(1.25, 2, -1, -2)\n", "\n", "#print(f\"Los coeficientes del polinomio: {pol1.coeficientes}\")\n", "\n", "#print(f\"El coeficiente de grado 2 es: {pol1.getCoeficiente(2)}\")\n", "\n", "#print(f\"El grado del polinomio es: {pol1.getGrado()}\")\n", "\n", "#print(f\"El polinomio en x=2.0 vale: {pol1.evalua(2.0)}\")\n", "\n", "#puntos1 = pol1.evaluaF()\n", "\n", "#pol2 = Polinomio(2, 0, 0)\n", "#puntos2 = pol2.evaluaF()\n", "\n", "#import matplotlib.pyplot as plt \n", "#x, y = zip(*puntos1)\n", "#plt.plot(x, y)\n", "#x, y = zip(*puntos2)\n", "#plt.plot(x, y)\n", "#plt.show()" ] }, { "cell_type": "markdown", "id": "1b4528b1-cd90-495e-ba86-eef829b61f49", "metadata": {}, "source": [ "## Ejercicios propuestos (y no resueltos)\n", "\n", "A continuación se enuncian unos pocos ejercicios que deberían poderse resolver con los conocimientos adquiridos en este tema de introducción a Python." ] }, { "cell_type": "markdown", "id": "4e2dc340-7b02-4274-82ac-9bd25c8e61a8", "metadata": {}, "source": [ "***\n", "**Ejercicio B.13 (sin resolver):**\n", "\n", "Programemos un juego muy sencillo: El juego comienza saludando al jugador y proponiéndole que adivine un número entero entre 1 y 100. El usuario debe entonces introducir un número. Entonces:\n", "+ Si el número es el correcto el programa felicita al jugador y acaba el programa\n", "+ Si el número no es el correcto el programa se lo indica al jugador diciéndole ```mayor``` o ```menor``` y vuelve a permitir que el usuario haga un intento. Este proceso se repetirá hasta que el jugador acierte." ] }, { "cell_type": "markdown", "id": "28d08a50-2b6a-44f1-b2e5-e7813166d0d7", "metadata": {}, "source": [ "***\n", "**Ejercicio B.14 (sin resolver):**\n", " \n", "Programa el [juego del ahorcado](https://es.wikipedia.org/wiki/Ahorcado_(juego))." ] }, { "cell_type": "markdown", "id": "fa91e3d8-3048-4ba1-92d2-c8a4cc24ffba", "metadata": {}, "source": [ "***\n", "**Ejercicio B.15 (sin resolver):**\n", "\n", "Haz un programa que dibuje el [fractal de Mandelbrot](https://es.wikipedia.org/wiki/Conjunto_de_Mandelbrot) en el cuadro delimitado por los números complejos ```(-2.0,-0.9)``` y ```(0.5,0.9)``` a intervalos de ```0.05```. Como todavía no tenemos mucha experiencia con la representación de gráficos vamos a pintarlo con ```print``` y el símbolo ```*```. Como número máximo de iteraciones para determinar si el punto pertenece al conjunto de Mandelbrot podemos usar ```100```. Deberías obtener un resultado similar a:\n", "``` \n", " * \n", " **** \n", " **** \n", " **** \n", " ** * \n", " * ********** \n", " ****************** \n", " ***************** \n", " * ***************** \n", " ******************* \n", " *********************** \n", " ********************* \n", " * *** ********************** \n", " ******* ********************** \n", " ********* ********************** \n", " ********* ********************** \n", " ** ********* ********************* \n", " * ************************************ \n", " ** ********* ********************* \n", " ********* ********************** \n", " ********* ********************** \n", " ******* ********************** \n", " * *** ********************** \n", " ********************* \n", " *********************** \n", " ******************* \n", " * ***************** \n", " ***************** \n", " ****************** \n", " * ********** \n", " ** * \n", " **** \n", " **** \n", " **** \n", " * \n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.16" } }, "nbformat": 4, "nbformat_minor": 5 }