MORGALLANA O BOTÓN DE ORO. FLOR TÍPICA DE LA LAURISILVA. MONTE DEL AGUA. LOS SILOS, NOROESTE DE TENERIFE. |
¡Por fin ha llegado la hora! Vamos a aplicar lo que hemos aprendido hasta ahora para construir nuestros primeros scripts.
Pueden coexistir varias maneras de codificar, mostrando todas ellas una estructura más o menos similar y, por descontado, devolviendo su ejecución el mismo resultado. Eso sí, como sucede con casi todo en la vida, unas son más preferibles que otras. Siempre habrá un script mejor que otros. En consecuencia, nos podemos plantear la siguiente cuestión: ¿Cuál es el mejor? Pues aquél que mejor entronque con la "filosofía" de Python, una filosofía que, como podemos comprobar en el siguiente enlace que dejo a continuación, es muy zen: ZEN-DE-PYTHON-PEP20 . Será nuestra codificación más clara, la más sencilla, aquélla que emplee la menor cantidad posible de recursos de codificación, la más elegante...
Creemos, sin embargo, que debemos hacer una puntualización, más personal, en este sentido. En algunos de los documentos que hemos consultado para elaborar este manual se insiste en crear casi desde el principio una codificación más elegante, más depurada, evitando a toda costa errores de estilo de programador novato, etc. Vamos a ver. Eso está muy bien, por supuesto que sí. Pero desde el punto de vista pedagógico a partir del cual ponemos el ánimo de este manual. lo más importante de un programa que codifiquemos es que funcione, que se ejecute correctamente, que sea eficaz en su cometido (la eficiencia ya vendrá después) y que "cumpla con lo que promete". Y punto pelota.
Otra cosa muy distinta es que cuando dejemos de ser novatos porque el tiempo y la experiencia nos doten de arte, de conocimientos y recursos, podamos codificar scripts más sencillos, mejor estructurados, más "finos" con respecto al uso de herramientas, explicitación de algoritmos, etc. Esto sería un plus añadido a nuestra capacidad como programadores, un plus deseable que hará de nosotros mejores y más solventes programadores. Aquéllo que "marca la diferencia".
Por ahora estamos aprendiendo, estamos conociendo el lenguaje, estamos inmersos en todo un proceso de asimilación de contenidos. Por eso, lo importante, lo prioritario es que APRENDAMOS a programar en Python, que nos planteemos diseñar un script o programa para resolver una cuestión... y que consigamos hacerlo.
BARRANCO DE GUARIA, MACIZO DE TENO, NOROESTE DE TENERIFE |
La elegancia, el buen estilo, la finura,... todo eso vendrá después, con el tiempo, la experiencia, la dedicación y el deseo, individual e intransferible de cada uno de nosotros, de ser cada vez mejor en lo que hacemos.
Queremos establecer una distinción entre lo que acabamos de comentar y lo que se conoce en Python como el PEP8 (o "pepocho", como lo llamamos cariñosamente), una especie de minimanual de estilos de codificación. La aplicación de este último es altamente recomendable y perfectamente útil en nuestros scripts desde el primer momento. Viene a ser algo así como aprender a conducir un coche aplicando desde el minuto uno los consejos de conducción eficiente y de ahorro energético: no son necesarias para aprender a conducir y a circular por nuestras carreteras pero nos permitirán hacerlo mejor, tanto para nosotros mismos como para los demás. Por eso la podemos aplicar desde el principio en tanto que nos ayudará a desterrar malos hábitos en la programación y a clarificar nuestro código. Continuando con la analogía, lo primero (la elegancia, el buen estilo, la finura,...) vendría a ser como un compendio de buenas prácticas en la carretera: procurar mantener la equidistancia entre las líneas de nuestro carril de circulación; no acelerar desde el primer momento en que ingresamos a un carril de incorporación a la autopista, no vaya a ser que nos quedemos parados al final de la misma, sin recorrido suficiente para incorporarnos a la autopista con una velocidad adecuada; facilitar la incorporación de los otros pasándonos al siguiente carril siempre que sea posible; no olvidarnos las cadenas cuando sabemos que va a nevar; tomar las curvas con el máximo ángulo posible para ganar estabilidad sobre el firme; etc.
El PEP8, pepocho, introduce una serie de normas de escritura aceptadas por convención entre la comunidad de programadores en Python, con el propósito loable de clarificar nuestros programas todo lo posible y hacerlo fácilmente legible (e inteligible) para cualquier programador del lenguaje en cualquier parte del mundo.
De hecho, algunas de sus normas de estilo ya las hemos adoptado en algunos de nuestros ejemplos: dejar un espacio o carácter en blanco en torno a los operadores y a continuación de las comas; procurar en la medida de lo posible hacer comentarios aclaratorios lo más escuetos posibles; etc.
Terminamos con la escueta y acertada definición propuesta por don Arturo Fernández Montoro, ingeniero de software senior de RED Interactive Agency, EEUU, y autor del libro "Python al descubierto", 2ª edición revisada, Ed. RC Libros, 2012, bic:umx con ISBN 978-84-939450-4-6, en su página 251:
"(http:\\www.python.org/dev/peps/pep-0008) define una completa guía de estilo, considerada como un estándar para código Python. El módulo PEP8 puede comprobar automáticamente si un script es compatible con las reglas fijadas en PEP8"
Además de lo que ya hemos dicho, muchos IDLEs e IDEs de Python que "circulan" por la web contienen un analizador de estilo basado en el PEP8 que actúan de manera automática sobre los códigos señalando las incongruencias y, en algunos casos, también corrigiéndolas.
Nuestro modesto IDLE "de serie", si bien incorpora algún detalle en este sentido, como una identación (sangría) preestablecida por defecto en cuatro espacios, y no una tabulación (tabs) de acuerdo a la especificación del PEP8, no alcanza a mucho más: casi todo dependerá de nosotros bajo la premisa de crear hábitos consecuentes con las buenas prácticas en programación.
Ya veremos con algo más de profundidad diferentes aspectos relacionados con esta guía de estilo consensuada. Realmente, no es muy compleja, algo prolija, sí, pero fácilmente asimilable, cuando menos, en sus apartados más importantes. De vez en cuando mostraremos alguna que otra etiqueta en los ejemplos para que nos vayamos acostumbrando a su uso, procurando siempre que nuestro proceso de aprendizaje discurra de la manera más natural posible.
Venga, vamos allá:
"(http:\\www.python.org/dev/peps/pep-0008) define una completa guía de estilo, considerada como un estándar para código Python. El módulo PEP8 puede comprobar automáticamente si un script es compatible con las reglas fijadas en PEP8"
Además de lo que ya hemos dicho, muchos IDLEs e IDEs de Python que "circulan" por la web contienen un analizador de estilo basado en el PEP8 que actúan de manera automática sobre los códigos señalando las incongruencias y, en algunos casos, también corrigiéndolas.
Nuestro modesto IDLE "de serie", si bien incorpora algún detalle en este sentido, como una identación (sangría) preestablecida por defecto en cuatro espacios, y no una tabulación (tabs) de acuerdo a la especificación del PEP8, no alcanza a mucho más: casi todo dependerá de nosotros bajo la premisa de crear hábitos consecuentes con las buenas prácticas en programación.
Ya veremos con algo más de profundidad diferentes aspectos relacionados con esta guía de estilo consensuada. Realmente, no es muy compleja, algo prolija, sí, pero fácilmente asimilable, cuando menos, en sus apartados más importantes. De vez en cuando mostraremos alguna que otra etiqueta en los ejemplos para que nos vayamos acostumbrando a su uso, procurando siempre que nuestro proceso de aprendizaje discurra de la manera más natural posible.
Venga, vamos allá:
LAGUNAS DE ERJOS, SISTEMA LACUSTRE ARTIFICIAL AL PIE MISMO DEL PASO DE ERJOS, EN EL CENTRO DE LA ISLA, QUE PERMITE ATRAVESAR LA DORSAL NORTE DE TENERIFE PARA PASAR AL VALLE DE SANTIAGO, AL OESTE. |
1.- CÁLCULO DEL ÁREA DE UN TRIÁNGULO DADOS SU BASE Y SU ALTURA.
¡Voilá! ¡Ya lo tenemos! Analicémoslo un poco, ¿de acuerdo?
1. Aquí hemos puesto un título a nuestro programa para saber qué estamos haciendo. Hemos recurrido a un comentario de línea, recordemos, aquél que empieza por almohadilla, #, y se esfuerza por ocupar la menor cantidad posible de líneas de código.
2. y 3. Introducimos los datos que necesitamos: la base y la altura del triángulo. Como podemos ver, hemos declarado una variable para cada dato procurando que el nombre del identificador que le hemos proporcionado refiera su naturaleza en la medida de lo posible, lo que redunda en beneficio de la legibilidad de nuestro código.
4. Declaramos una nueva variable, a la que hemos llamado "area", que recoja el algoritmo (en la RAE, la primera acepción de un algoritmo es la de un "conjunto ordenado y finito de operaciones que permite hallar la solución de un problema") o fórmula que, matemáticamente, permite determinar el área de un triángulo, esto es, la base por la altura dividida entre 2, y que "traducimos" a la sintaxis de Python.
En la mayoría de los casos, se trata de eso: traducir fórmulas matemáticas que determinan cosas (áreas de figuras geométricas, volúmenes de sólidos, factoriales, álgebra, derivación, trigonometría, ortografía, topología, estadística, integración, constantes físicas, equivalencias químicas, cinética, e innumerables aspectos más del conocimiento) al lenguaje de Python. En nuestra propuesta hacemos, precísamente, éso: traducir una fórmula matemática al lenguaje de Python, con lo que construimos una expresión, tal y como lo hemos visto con anterioridad.
5. Llamamos a la función print() para que impresione en pantalla el resultado de la ejecución del script. En este caso, le pasamos como argumento una string para que nos salga más coqueta la cosa. Observemos que tras los dos puntos dejamos un espacio en blanco para que no nos salga un texto apelmazado. Colocamos la coma preceptiva para separar argumentos y escribimos el nombre de la variable a la que hemos asignado el algoritmo.
Pulsamos ENTER y ya tenemos el resultado en el SHELL.
Aquí presentamos una nueva función preconstruida, una función built-in: la función round(), del inglés "to round", "redondear", y que será la encargada de redondear los resultados que se obtengan de acuerdo al criterio que hayamos impuesto. Como podemos ver en 9., esta función admite dos argumentos: el primero, number, hace referencia al número que queremos redondear (o, como ya sabemos, a la variable que lo almacena). En el caso que nos ocupa, será el número representado por la variable "area" y es por eso por lo que escribimos su identificador como argumento y no 28.79999..., que es mucho, muchísimo más largo de escribir. Recordemos que una fórmula, un algoritmo, es ya un número en sí mismo: aquél que resulta de su ejecución:
AREA = (B * H) / 2 = 28.79999...7
1. Aquí hemos puesto un título a nuestro programa para saber qué estamos haciendo. Hemos recurrido a un comentario de línea, recordemos, aquél que empieza por almohadilla, #, y se esfuerza por ocupar la menor cantidad posible de líneas de código.
2. y 3. Introducimos los datos que necesitamos: la base y la altura del triángulo. Como podemos ver, hemos declarado una variable para cada dato procurando que el nombre del identificador que le hemos proporcionado refiera su naturaleza en la medida de lo posible, lo que redunda en beneficio de la legibilidad de nuestro código.
4. Declaramos una nueva variable, a la que hemos llamado "area", que recoja el algoritmo (en la RAE, la primera acepción de un algoritmo es la de un "conjunto ordenado y finito de operaciones que permite hallar la solución de un problema") o fórmula que, matemáticamente, permite determinar el área de un triángulo, esto es, la base por la altura dividida entre 2, y que "traducimos" a la sintaxis de Python.
En la mayoría de los casos, se trata de eso: traducir fórmulas matemáticas que determinan cosas (áreas de figuras geométricas, volúmenes de sólidos, factoriales, álgebra, derivación, trigonometría, ortografía, topología, estadística, integración, constantes físicas, equivalencias químicas, cinética, e innumerables aspectos más del conocimiento) al lenguaje de Python. En nuestra propuesta hacemos, precísamente, éso: traducir una fórmula matemática al lenguaje de Python, con lo que construimos una expresión, tal y como lo hemos visto con anterioridad.
5. Llamamos a la función print() para que impresione en pantalla el resultado de la ejecución del script. En este caso, le pasamos como argumento una string para que nos salga más coqueta la cosa. Observemos que tras los dos puntos dejamos un espacio en blanco para que no nos salga un texto apelmazado. Colocamos la coma preceptiva para separar argumentos y escribimos el nombre de la variable a la que hemos asignado el algoritmo.
Pulsamos ENTER y ya tenemos el resultado en el SHELL.
Aquí presentamos una nueva función preconstruida, una función built-in: la función round(), del inglés "to round", "redondear", y que será la encargada de redondear los resultados que se obtengan de acuerdo al criterio que hayamos impuesto. Como podemos ver en 9., esta función admite dos argumentos: el primero, number, hace referencia al número que queremos redondear (o, como ya sabemos, a la variable que lo almacena). En el caso que nos ocupa, será el número representado por la variable "area" y es por eso por lo que escribimos su identificador como argumento y no 28.79999..., que es mucho, muchísimo más largo de escribir. Recordemos que una fórmula, un algoritmo, es ya un número en sí mismo: aquél que resulta de su ejecución:
AREA = (B * H) / 2 = 28.79999...7
CALLE TRADICIONAL DE LA VILLA Y PUERTO DE GARACHICO, NORTE DE TENERIFE. |
Es necesario traer a colación aquí un apunte. Al solicitar dos dígitos, siempre los más próximos tras el punto decimal y de izquierda a derecha, de entre la miríada de decimales, en el caso que nos ocupa, nos muestra uno sólo, 8, y esto se debe a que con un nueve periódico como decimal (el 7 del final tiene su explicación desde el punto de vista de los números binarios, por los que suspira la computación moderna y en lo que no vamos a entrar), la tendencia hacia el ocho (casi, casi, casi, lo es) es tan obvia que Python, en lugar de devolvernos 28.79, él solito efectúa un redondeo más exacto y nos lo asimila a 8 como decimal único, independientemente del número de decimales que le hubiéramos solicitado: 4, 5, 10, etc.
7. Aquí pedimos un nuevo redondeo. En esta ocasión pasamos un único argumento, 'area', por los que nos devuelve un número entero, int, el 29, en el ejemplo.
Vamos a concluir con la función round() señalando algunas peculiaridades suyas más:
- Si utilizamos el 0 como segundo argumento nos devuelve un número de punto flotante, float, donde Python ha eliminado todos los número decimales sustituyéndolos por ceros. Nos devuelve un float puro.
- Si pasamos como primer argumento un número entero y, como segundo, un número negativo, Python sustituirá tantos números al final de la cifra devuelta sustituyéndolos por ceros como sea el valor negativo: con -1, décimas; con -2, centésimas; con -3, milésimas; con -4, diezmilésimas;... y así sucesivamente. Si igualamos o superamos al número negativo la cantidad total de dígitos que tiene la cifra, Python nos devuelve 0.
- Cuando aplicamos lo que acabamos de decir a un número float, ejecuta dos acciones distintas en función del valor del número negativo:
3.2 Con cualquier número negativo por debajo de -1, devuelve 0.0
Normalmente se producen estos comportamientos. A veces, puede ocurrir alguna alteración, pero esto se debe a que Python guarda toda su información, números incluidos, utilizando el sistema binario provocando alguna devolución extraña o inesperada.
Como no puede ser menos, ejemplos al canto:
8. Aquí tenemos un ejemplo de cómo introducir una función dentro de otra, round() dentro de print() para ahorrar espacio y memoria (ya sabemos que print() es una función "todo terreno"). Esta sería una formulación más "elegante" que las anteriores, en tanto que resuelve el mismo problema con menos líneas de código, sin llegar al exceso. ¿Lo vamos pillando?
¿Qué tal? Fácil, ¿no?
Permíteme ladrar un poquito para resaltar un detalle en el que seguro que ya hemos caído en la cuenta. Cuando escribimos los nombres de los identificadores de variables, si las escribimos en castellano, evitamos utilizar tildes e, incluso si es posible, las 'ñ'. En otros idiomas se suele hacer lo propio con signos ortográficos y/o tipos de letras que son propios o exclusivos de un determinado idioma o dialecto, como ^ o Ç . ¿Por qué motivo? Porque a pesar de que Python está codificado en caracteres Unicode y puede leerlo y entenderlo perfectamente, podría muy, muy raramente, darse algún tipo de conflicto. Por otra parte, la lengua más o menos franca de nuestro tiempo, como en su momento en Europa lo fue el latín, es hoy el inglés. Y los teclados están más adaptados a este idioma que a otros en general, que no utiliza caracteres propios, como el castellano, el alemán, el noruego, el portugués, etc. Recordemos: los teclados se suelen adaptar a las necesidades ortográficas de cada idioma, pero ortográficamente y en caracteres latinos, se puede escribir correctamente el inglés en todos ellos. Por último, si escribimos sin signos y/o letras "extrañas", seremos más compresibles para cualquier persona que nos lea, fuere cual fuese su procedencia. ¡Guau! Me ha entrado sed. Me voy a beber un par de buches y ahora vuelvo.
2.- CALCULEMOS EL VOLUMEN DE UNA ESFERA SABIENDO QUE SU DIÁMETRO ES DE 12 CMTS.
Para resolver este problema mediante un script Python, primero, como es obvio, tenemos que conocer la fórmula matemática del volumen de una esfera, en este caso, V = (4 · PI · (R··3)) / 3. Del algoritmo conocemos todos los datos salvo el radio, R. Sin embargo, el problema nos proporciona el diámetro de la esfera, que es de 12 cmts. Sabemos que el diámetro es igual a 2 · R, siendo R el radio; Así pues, conoceríamos el valor de R tan sólo dividiendo el diámetro entre 2. En consecuencia, tendremos dos scripts: el primero nos permitirá hallar el radio, R, de la esfera a partir de su diámetro. El segundo, conociendo el radio, R, responderá a la cuestión planteada en el problema. Vamos a verlo:
1. Declaramos la variable que identificamos como 'diámetro' y le asignamos el valor 12.
2. Utilizamos el algoritmo que ya mencionamos (expresión) para calcular la variable 'radio'.
3. Proponemos una función print() para que se nos imprima en pantalla el número tan bonito que nos sale. Recordemos que la función print() carece de utilidad alguna a la hora de codificar: tan sólo muestra resultados al usuario/programador. A nosotros como programadores nos resulta conveniente como mecanismo de control d ejecución, de tal modo que los resultados esperados coincidan con los que obtiene Python y saber que estamos haciendo bien las cosas. Si queremos podemos insertar la función round() dentro de print() como previsión de que no se nos desmadren los decimales aunque, en el ejemplo, ya sabemos que tendremos una división exacta, con resto = 0.
4. Creamos la variable con el identificador 'pi' y le asignamos como valor la constante que todos conocemos: 3.1416. Para esta ocasión, en vista a hacerlo más adelante, no vamos a usar ninguna importación desde el módulo math de la librería estándar de Python desde el que podemos llamar a PI. Como decimos, eso vendrá más adelante.
5. En esta segunda declaración aprovechamos el radio que ya obtuvimos en la primera y que almacenamos en la variable homónima, y elaboramos la expresión correspondiente, que asignamos a su vez a la variable 'volumen'.
6. Finalmente, para mostrar el resultado, llamamos nuevamente a la función print(), y como argumento le pasamos, primero, una string que anuncia el resultado; la coma preceptiva, que separa el siguiente elemento a mostrar; la función round() que lleva como argumentos a la variable 'volumen', la coma, y el número de dígitos que llevará el redondeo, 2; una nueva coma; y, finalmente, una nueva string para significar las medidas propias de los volúmenes de los cuerpos sólidos.
Podemos presentar una nueva propuesta, un tanto más "grosera", donde incluimos el algoritmo dentro de la función round() que, a su vez, está dentro de la función print(), y en la que pedimos un número (number) pero sin incluir esta vez cifra alguna para acotar el número de decimales:
Esta codificación, perfectamente operativa como podemos comprobar, a pesar de que acorta significativamente el tamaño del bloque de código, no es muy "elegante", que digamos. Cuando trabajamos con algoritmos resulta más útil y conveniente desarrollarlos fuera del print(), dejándola sólo para lo que realmente está, que es para mostrar resultados, e incluir en la función la variable a la que está asignado: el módulo se clarifica más y gana en legibilidad.
El ejemplo de arriba es otra opción. De hecho, constituye la opción más correcta. En ella prescindimos de llamadas a print() innecesarias, incluye comentarios pertinentes para seguir el desarrollo del script, aplicamos correctamente las recomendaciones del PEP8 y no damos por hecho que conocemos de antemano el valor de la constante PI. En 1. lo que hacemos, como ya dejamos entrever en los ejemplos anteriores, es acudir a un módulo de la librería de Python. ¿A cuál? Como buscamos PI, que es una constante matemática, tenemos que acudir a la librería estándar y localizar el módulo adecuado para importar, concretamente, math. En la librería de Python, que obtenemos por defecto cuando nos descargamos el lenguaje en nuestro disco duro y a la que tenemos acceso franco mediante importaciones simples, tenemos a nuestra disposición un gran número de módulos y paquetes que podemos importar para facilitar nuestra labor. Por ejemplo, tenemos módulos como tkinter, datetime, codecs, random, crypt, operator, symbol, etc ¿Para qué lo hacemos? Para que nos proporcione el valor del número PI que buscamos. ¿Cómo lo hacemos? Recurriendo a la sintaxis de importación, que aquí vamos a ver sin entrar en detalles, para que nos vaya sonando. La estudiaremos mejor en su debido momento más adelante en este manual:
from nombre_del_módulo import dato/función
2. Utilizamos el algoritmo que ya mencionamos (expresión) para calcular la variable 'radio'.
3. Proponemos una función print() para que se nos imprima en pantalla el número tan bonito que nos sale. Recordemos que la función print() carece de utilidad alguna a la hora de codificar: tan sólo muestra resultados al usuario/programador. A nosotros como programadores nos resulta conveniente como mecanismo de control d ejecución, de tal modo que los resultados esperados coincidan con los que obtiene Python y saber que estamos haciendo bien las cosas. Si queremos podemos insertar la función round() dentro de print() como previsión de que no se nos desmadren los decimales aunque, en el ejemplo, ya sabemos que tendremos una división exacta, con resto = 0.
4. Creamos la variable con el identificador 'pi' y le asignamos como valor la constante que todos conocemos: 3.1416. Para esta ocasión, en vista a hacerlo más adelante, no vamos a usar ninguna importación desde el módulo math de la librería estándar de Python desde el que podemos llamar a PI. Como decimos, eso vendrá más adelante.
5. En esta segunda declaración aprovechamos el radio que ya obtuvimos en la primera y que almacenamos en la variable homónima, y elaboramos la expresión correspondiente, que asignamos a su vez a la variable 'volumen'.
6. Finalmente, para mostrar el resultado, llamamos nuevamente a la función print(), y como argumento le pasamos, primero, una string que anuncia el resultado; la coma preceptiva, que separa el siguiente elemento a mostrar; la función round() que lleva como argumentos a la variable 'volumen', la coma, y el número de dígitos que llevará el redondeo, 2; una nueva coma; y, finalmente, una nueva string para significar las medidas propias de los volúmenes de los cuerpos sólidos.
Podemos presentar una nueva propuesta, un tanto más "grosera", donde incluimos el algoritmo dentro de la función round() que, a su vez, está dentro de la función print(), y en la que pedimos un número (number) pero sin incluir esta vez cifra alguna para acotar el número de decimales:
Esta codificación, perfectamente operativa como podemos comprobar, a pesar de que acorta significativamente el tamaño del bloque de código, no es muy "elegante", que digamos. Cuando trabajamos con algoritmos resulta más útil y conveniente desarrollarlos fuera del print(), dejándola sólo para lo que realmente está, que es para mostrar resultados, e incluir en la función la variable a la que está asignado: el módulo se clarifica más y gana en legibilidad.
ANTIGUO ABREVADERO EXCAVADO EN PIEDRA TOSCA, JUNTO A UN CAMINO REAL EN LAS MEDIANÍAS DE SAN MIGUEL, SUR DE TENERIFE. |
El ejemplo de arriba es otra opción. De hecho, constituye la opción más correcta. En ella prescindimos de llamadas a print() innecesarias, incluye comentarios pertinentes para seguir el desarrollo del script, aplicamos correctamente las recomendaciones del PEP8 y no damos por hecho que conocemos de antemano el valor de la constante PI. En 1. lo que hacemos, como ya dejamos entrever en los ejemplos anteriores, es acudir a un módulo de la librería de Python. ¿A cuál? Como buscamos PI, que es una constante matemática, tenemos que acudir a la librería estándar y localizar el módulo adecuado para importar, concretamente, math. En la librería de Python, que obtenemos por defecto cuando nos descargamos el lenguaje en nuestro disco duro y a la que tenemos acceso franco mediante importaciones simples, tenemos a nuestra disposición un gran número de módulos y paquetes que podemos importar para facilitar nuestra labor. Por ejemplo, tenemos módulos como tkinter, datetime, codecs, random, crypt, operator, symbol, etc ¿Para qué lo hacemos? Para que nos proporcione el valor del número PI que buscamos. ¿Cómo lo hacemos? Recurriendo a la sintaxis de importación, que aquí vamos a ver sin entrar en detalles, para que nos vaya sonando. La estudiaremos mejor en su debido momento más adelante en este manual:
from nombre_del_módulo import dato/función
En nuestro caso particular, como nuestro módulo es math y nuestro dato/método es PI, lo escribimos así:
from math import pi
from math import pi
Cuando trabajamos con divisiones, el cociente y el resto de las operaciones matemáticas que se efectúen a continuación pueden arrojar un número considerable de decimales. A título personal, preferimos insertar una función round() al final, y no entre medias: con los decimales completos mientras se vaya ejecutando el programa conseguiremos resultados más ajustados. Redondear el resultado final, nos dará una cifra más exacta, aunque sólo pasemos dos, tres o cinco decimales.
Y ya que estamos, podemos perfilar todavía mejor nuestro pequeño script sustituyendo el operador aritmético de potencia por la función preconstruida pow(). Esta función pow(), del inglés "power", 'poder', calcula la potencia de un número pasado como argumento. Es decir, hace exactamente lo mismo que el doble asterisco. La función puede llevar tres argumentos, 'x', 'y' y 'z' (éste último, como en el cuadro de información de Python se nos muestra entre corchetes, se nos avisa de que se trata de un argumento opcional, mientras que 'x' e 'y' son argumentos obligatorios), y nos devuelve un "number", un número, ya sea de tipo int o de tipo float. El primer argumento obligatorio, 'x', es la base; 'y' es el exponente, la potencia a la que queremos elevar al primero; y 'z' un divisor del número resultante de elevar 'x' a 'y'. En este caso, con los tres argumentos posibles pasados a la función, power() nos devolvería el resto de la división.
En consecuencia, observemos que la función pow() sustituye, con dos argumentos, al operador aritmético de potencia (**), y con los tres argumentos, al operador aritmético de resto (%), eso sí, siempre y cuando el dividendo sea 'x' elevado a 'y' y el divisor, 'z'.
Y ya que estamos, podemos perfilar todavía mejor nuestro pequeño script sustituyendo el operador aritmético de potencia por la función preconstruida pow(). Esta función pow(), del inglés "power", 'poder', calcula la potencia de un número pasado como argumento. Es decir, hace exactamente lo mismo que el doble asterisco. La función puede llevar tres argumentos, 'x', 'y' y 'z' (éste último, como en el cuadro de información de Python se nos muestra entre corchetes, se nos avisa de que se trata de un argumento opcional, mientras que 'x' e 'y' son argumentos obligatorios), y nos devuelve un "number", un número, ya sea de tipo int o de tipo float. El primer argumento obligatorio, 'x', es la base; 'y' es el exponente, la potencia a la que queremos elevar al primero; y 'z' un divisor del número resultante de elevar 'x' a 'y'. En este caso, con los tres argumentos posibles pasados a la función, power() nos devolvería el resto de la división.
En consecuencia, observemos que la función pow() sustituye, con dos argumentos, al operador aritmético de potencia (**), y con los tres argumentos, al operador aritmético de resto (%), eso sí, siempre y cuando el dividendo sea 'x' elevado a 'y' y el divisor, 'z'.
ALTOS DE IFONCHE, VILAFLOR, CENTRO-SUR DE TENERIFE. |
3.- CÁLCULO Y APLICACIÓN DE UN IMPUESTO, POR EJEMPLO, EL IVA, Y UNA BONIFICACIÓN OPCIONAL (SI EL CLIENTE QUISIERA HACER USO DE ELLA O PRESERVARLA PARA OTRA OCASIÓN), EL 5% DEL TOTAL POR SER CLIENTE REGISTRADO DE, PONGAMOS POR CASO, UNA TIENDA DE ROPA DE MARCA.
Evidentemente, contamos con una caja registradora o, si somos más modernos, una TPV (Terminal de Punto de Venta). Supongamos que compramos una camisa de seda por 120€, una corbata por 100€ y un terno de verano por 200€.
1., 2. y 3. Declaramos las variables correspondientes asignando a cada una su valor (pvp), los sumamos y almacenamos en 4. el valor total, esto es, 420.0€.
5. Ahora que ya conocemos el total aplicamos sobre él la carga impositiva, como hemos dicho, el IVA, por un 12 % imaginemos, sobre el total de la compra, tal y como apreciamos en 6. , dándonos como resultado 50.4.
7. Ahora ya sólo nos falta sumarle al total de compra, 420.0€, el IVA correspondiente, 50.4, siendo el precio final, que reducimos a dos decimales con la función round(), 470.4.
En el caso de que el cliente solicitara la bonificación del 5%, pasamos al punto 8. donde calculamos el total de la bonificación en euros al que tiene derecho nuestro cliente, en este caso, 21.0€.
9. Aquí restamos la bonificación del total y obtenemos la cantidad final: 399.0€.
10. Para finalizar, sobre este mismo valor aplicamos el IVA que habíamos calculado para el total original de 420.0€ quedándonos con el redondeo que solicitamos en 11. para obtener el resultado definitivo: 449.4€.
¿Verdad que no es nada complicado? Pues así trabajan básicamente las cajas registradoras/TPVs.
Tan sólo se trata de encadenar varias expresiones simples para obtener un resultado concreto, en un orden o flujo específico. En estos primeros ejemplos, nos interesa más y nos resulta más productivo desde el punto de vista como futuros programadores el comprender bien el despliegue lógico de los programas, su lógica implícita antes que el auxilio de tal o cual recurso, si conviene o no "abusar" de la función print(), la calidad/idoneidad de las variables (si son demasiado largas, y, como resultado, tardan más en escribirse; si resultan más o menos descriptivas; si "abultan" el programa; si demandan demasiados recursos de memoria, etc.), si su comprensión deviene más o menos engorrosa, etc. fijémonos primero en el esquema y después en el relleno: primero está el esqueleto, y después todo lo que se sostiene a partir de él, primero "anatomía" y después "fisiología".
Por cierto y como curiosidad, aunque seguro que en algún momento lo encontraremos muy útil. Si nuestra TPV registrara una cuenta total de, supongamos, 4723.53€ y quisiéramos marcar los millares, podríamos recurrir al siguiente código, muy rarito él ya que estamos, que nos separa los millares al modo anglosajón, con comas en lugar de puntos, en tanto que separarlos así, sobre todo si usamos números de tipo float que utilizan el punto para separar la parte entera de la decimal, a parte de generar desconcierto no parece que sea fácil de resolver con una simple línea de código.
Para profundizar más en el tema a ver si nos despejamos el caletre, no estaría de más consultar la entrada EL MÉTODO STR.FORMAT(ARGS, **KWARGS) AL DESCUBIERTO.
Ladraré bajito que la cosa tiene que ver con los distintos formatos de caracteres que se utilizan en programación, y que se suelen emplear a uno y otro lado del atlántico. Echemos un vistazo a la siguiente solución:
Este formato, nunca mejor dicho, de '{:,}'.format(), tiene ciertas aplicaciones interesantes que ya veremos en su debido momento. Quedémonos por el momento con la curiosidad.
5. Ahora que ya conocemos el total aplicamos sobre él la carga impositiva, como hemos dicho, el IVA, por un 12 % imaginemos, sobre el total de la compra, tal y como apreciamos en 6. , dándonos como resultado 50.4.
7. Ahora ya sólo nos falta sumarle al total de compra, 420.0€, el IVA correspondiente, 50.4, siendo el precio final, que reducimos a dos decimales con la función round(), 470.4.
En el caso de que el cliente solicitara la bonificación del 5%, pasamos al punto 8. donde calculamos el total de la bonificación en euros al que tiene derecho nuestro cliente, en este caso, 21.0€.
9. Aquí restamos la bonificación del total y obtenemos la cantidad final: 399.0€.
10. Para finalizar, sobre este mismo valor aplicamos el IVA que habíamos calculado para el total original de 420.0€ quedándonos con el redondeo que solicitamos en 11. para obtener el resultado definitivo: 449.4€.
¿Verdad que no es nada complicado? Pues así trabajan básicamente las cajas registradoras/TPVs.
Tan sólo se trata de encadenar varias expresiones simples para obtener un resultado concreto, en un orden o flujo específico. En estos primeros ejemplos, nos interesa más y nos resulta más productivo desde el punto de vista como futuros programadores el comprender bien el despliegue lógico de los programas, su lógica implícita antes que el auxilio de tal o cual recurso, si conviene o no "abusar" de la función print(), la calidad/idoneidad de las variables (si son demasiado largas, y, como resultado, tardan más en escribirse; si resultan más o menos descriptivas; si "abultan" el programa; si demandan demasiados recursos de memoria, etc.), si su comprensión deviene más o menos engorrosa, etc. fijémonos primero en el esquema y después en el relleno: primero está el esqueleto, y después todo lo que se sostiene a partir de él, primero "anatomía" y después "fisiología".
Por cierto y como curiosidad, aunque seguro que en algún momento lo encontraremos muy útil. Si nuestra TPV registrara una cuenta total de, supongamos, 4723.53€ y quisiéramos marcar los millares, podríamos recurrir al siguiente código, muy rarito él ya que estamos, que nos separa los millares al modo anglosajón, con comas en lugar de puntos, en tanto que separarlos así, sobre todo si usamos números de tipo float que utilizan el punto para separar la parte entera de la decimal, a parte de generar desconcierto no parece que sea fácil de resolver con una simple línea de código.
Para profundizar más en el tema a ver si nos despejamos el caletre, no estaría de más consultar la entrada EL MÉTODO STR.FORMAT(ARGS, **KWARGS) AL DESCUBIERTO.
Ladraré bajito que la cosa tiene que ver con los distintos formatos de caracteres que se utilizan en programación, y que se suelen emplear a uno y otro lado del atlántico. Echemos un vistazo a la siguiente solución:
VISTA DEL TEIDE Y DEL PICO VIEJO, A LA IZQUIERDA, DESDE EL "SOMBRERO" DE CHASNA, FORMACIÓN OROGRÁFICA COLINDANTE CON EL PARQUE NACIONAL DE LAS CAÑADAS DEL TEIDE. |
4.- SUPONGAMOS QUE TENEMOS A CINCO COLABORADORES EN UN EXPERIMENTO DE AGUDEZA VISUAL, EL MISMO PARA TODOS ELLOS, CONSTITUIDO POR 12 PREGUNTAS. ESTOS HAN SIDO SUS ACIERTOS: 8, 8, 7, 9, 7. NOS INTERESA CALCULAR LA MEDIA Y SU PORCENTAJE CON RESPECTO AL TOTAL DE PREGUNTAS:
Podemos seguir perfectamente el procedimiento: sumamos los resultados, los dividimos entre 5 para extraer la media y obtenemos 7.8. Para calcular el porcentaje acudimos nuevamente a nuestro ya conocido método de las strings str.format(). En esta ocasión, proponemos un encabezado con el texto "EL PORCENTAJE DE ACIERTOS ES DE:" y abrimos las llaves características de la sintaxis del método con el formato tipo {:. A continuación colocamos un par de números separados por un punto: el primero, normalmente, es 0, aunque podemos ver en el ejemplo que podemos poner otro número int cualquiera en su lugar, es preferible dejar siempre un 0.
El segundo desempeña una función similar a la 'y' de round(), devolviendo el número de decimales que queramos mostrar: 2, 4, 10, etc. Finalmente, como argumento de str.format() ponemos la variable 'media_de_aciertos' dividida por el total. Y con esto ya tenemos radiante, brillante, rutilante, nuestra media de aciertos: 65.00%.
5.- CALCULEMOS LA HIPOTENUSA DE UN TRIÁNGULO RECTÁNGULO SABIENDO QUE SU ÁREA ES DE 20 CMTS. CUADRADOS Y QUE UNO DE SUS CATETOS MIDE 5 CMTS.
1. Aquí procedemos por primera vez a una formulación abreviada para asignar valores a una serie de variables bastándonos para ello con una única línea de código. Se conoce como MÉTODO DE ASIGNACIÓN ABREVIADO. Como podemos ver, Python la reconoce sin problemas y asigna a cada variable su valor correspondiente de forma oportuna, siguiendo la premisa de que a la primera variable que encuentra, leyendo de izquierda a derecha, le asigna el primer valor que encuentra justo después del operador de asignación =; a la segunda variable, el segundo valor; a la tercera variable el tercer valor; y así sucesivamente. Obviamente, tanto las variables como los datos deben ir separados por comas para que Python los pueda distinguir y efectuar así las asignaciones apropiadas.
Como todo en la vida debe tener y tiene límites, las asignaciones abreviadas también las tienen, o deberían tenerlas. ¿Cuántas? Depende de cada cual, pero estaría bien no "montar" un auténtico batiburrillo de variables y valores en una misma línea de código. Para el caso proponemos un máximo de tres o cuatro, a lo sumo.
Como todo en la vida debe tener y tiene límites, las asignaciones abreviadas también las tienen, o deberían tenerlas. ¿Cuántas? Depende de cada cual, pero estaría bien no "montar" un auténtico batiburrillo de variables y valores en una misma línea de código. Para el caso proponemos un máximo de tres o cuatro, a lo sumo.
2. Proponemos la expresión que permite calcular la incógnita, el lado o cateto que nos falta, a partir de la fórmula que permite hallar el área del triángulo y que ya vimos en el primer ejemplo.
3. Como en Python no disponemos de un operador o función preconstruida para determinar la raíz cuadrada de un número, debemos importarla del módulo math de la librería estándar de Python, utilizando el nombre de sqrt, respetando en la construcción del bloque de código la recomendación del 'pepocho'.
4. La empleamos en el algoritmo H**2 = C1**2 + C2**2 => H = SQRT(C1**2 + C2**2) usando la expresión que aparece en el código, donde calculamos las potencias recurriendo a la función pow() en lugar de al doble asterisco. ¿Por qué lo hacemos así? Porque siempre es mejor recurrir a una función que para eso están y queda más bonito, con su punto de elegancia y todo.
3. Como en Python no disponemos de un operador o función preconstruida para determinar la raíz cuadrada de un número, debemos importarla del módulo math de la librería estándar de Python, utilizando el nombre de sqrt, respetando en la construcción del bloque de código la recomendación del 'pepocho'.
4. La empleamos en el algoritmo H**2 = C1**2 + C2**2 => H = SQRT(C1**2 + C2**2) usando la expresión que aparece en el código, donde calculamos las potencias recurriendo a la función pow() en lugar de al doble asterisco. ¿Por qué lo hacemos así? Porque siempre es mejor recurrir a una función que para eso están y queda más bonito, con su punto de elegancia y todo.
VISTA DEL PICO VIEJO EN PRIMER PLANO Y DEL TEIDE DETRÁS, DESDE EL PINAR DE ARGUAYO, EN GUÍA DE ISORA, OESTE DE TENERIFE. |
6.- UN POCO DE TRIGONOMETRÍA SENCILLA. CONOCIENDO LOS DATOS DEL TRIÁNGULO RECTÁNGULO DEL EJERCICIO ANTERIOR, VAMOS A CALCULAR EL SENO ALFA.
El seno alfa del ángulo de un triángulo rectángulo se define como la razón entre la hipotenusa y el cateto opuesto a la hipotenusa que, en nuestro caso, vamos a suponer que es el más corto (b, que vale 5 en lugar de c, que vale 8). La fórmula para calcular el seno es muy simple:
SENO_ALPHA = CATETO_OPUESTO-HIPOTENUSA / HIPOTENUSA
1. Podemos importar el seno (sin) del módulo math y de esta manera, nos ahorramos en 2. la declaración de una variable a la que asignemos una expresión que tengamos que describir (el "ahorro" conlleva una mayor eficiencia, una menor extensión del bloque de código, y una mayor claridad, lo que redunda en la optimización de nuestro script).
A la vista está que la resolución de este problema es muy fácil. Como ámbito de consulta podemos recurrir a la siguiente tabla que nos muestra las importaciones más comunes que se suelen invocar sobre el módulo math. Éste aglutina más opciones. Si queremos consultarlas no tenemos más que abrir la carpeta de MODULE DOCS y buscar en BUILT-IN MODULES (módulos preconstruidos: igual que contamos en Python con funciones preconstruidas, contamos también con módulos preconstruidos que nos facilitan la vida. Y clases preconstruidas, métodos preconstruidos, etc...) que es el primer apartado que nos salta a la vista. ¡Ah! ¡Y encima se indexan por orden alfabético!
5. Con esta otra expresión, obtenemos el mismo resultado que en la expresión anterior sólo que con signo negativo, proporcionando también en 6. una solución errónea.
¿Cómo resolverlo?
Pues acudiendo a una nueva función preconstruida de Python: abs(). La contracción "abs", del inglés, "absolute", es decir, "absoluto" traducido al castellano. Y eso es precisamente lo que nos ofrece: cualquier número (number) pasado como argumento de la función, nos será devuelto el número en cuestión sin tener en cuenta su signo, fuera este positivo o negativo.
7. Así podemos obtener un resultado ajustado ala especificación que se nos demandaba: "grados bajo cero". Recordemos que es un error decir "menos n grados bajo cero", donde n es un número racional cualquiera.
Existe, no obstante, otro método para obtener números positivos o negativos simplemente pasando a uno o al otro el valor inicial de la variable, tal y como podemos comprobar en el ejemplo siguiente:
Y con esto damos por terminado este capítulo, que ya es hora. Para darnos un pequeño respiro antes de pasar al siguiente, ¿qué tal si aprendemos un poquito más sobre nuestro IDLE? Venga, vamos allá.
La función integrada ord() trabaja con un único argumento en base al charset (conjunto de caracteres con el que trabaja el código máquina) de ASCII, de manera que que cuando pasamos un carácter nos devuelve un número entero que le corresponde en el charset. Veamos unos ejemplos:
Tengamos en cuenta que el carácter que pasemos a la función, sea una letra, un signo o un dígito, debemos hacerlo como string.
También podemos pasarle a la función caracteres Unicode, (\u****), y esperar que nos devuelva un nuevo entero. Veámoslo:
La función chr() por su parte, y de manera complementaria a ord(), nos devuelve el carácter que corresponde en Unicode al entero que le pasemos como argumento. Veámoslo:
Finalmente, para los que estemos interesados en conocer el zen de Python al que hacíamos breve referencia al comienzo de este apartado, tan sólo tenemos que teclear en nuestro IDLE la siguiente instrucción:
1. Podemos importar el seno (sin) del módulo math y de esta manera, nos ahorramos en 2. la declaración de una variable a la que asignemos una expresión que tengamos que describir (el "ahorro" conlleva una mayor eficiencia, una menor extensión del bloque de código, y una mayor claridad, lo que redunda en la optimización de nuestro script).
A la vista está que la resolución de este problema es muy fácil. Como ámbito de consulta podemos recurrir a la siguiente tabla que nos muestra las importaciones más comunes que se suelen invocar sobre el módulo math. Éste aglutina más opciones. Si queremos consultarlas no tenemos más que abrir la carpeta de MODULE DOCS y buscar en BUILT-IN MODULES (módulos preconstruidos: igual que contamos en Python con funciones preconstruidas, contamos también con módulos preconstruidos que nos facilitan la vida. Y clases preconstruidas, métodos preconstruidos, etc...) que es el primer apartado que nos salta a la vista. ¡Ah! ¡Y encima se indexan por orden alfabético!
LA CALETA DE ADEJE, ACANTILADOS DE TOBA Y PLAYA FÓSIL DESDE EL PUERTITO, ADEJE, SUROESTE DE TENERIFE |
7.- UN POCO DE CONTABILIDAD: IMAGINEMOS EL CASO DE UN GESTOR CONTABLE DE LA EMPRESA X. TAL EMPRESA QUIERE VENDER UNA DE SUS MÁQUINAS, YA MUY ANTIGUA, PARA CONSEGUIR ALGO DE LIQUIDEZ. TAL MÁQUINA, UNA FRESADORA DE ACERO, SE ADQUIRIÓ EN SU MOMENTO POR 10.000,00€. SIN EMBARGO, SE CUANTIFICÓ QUE A SU VALOR DE ADQUISICIÓN HABRÍA QUE RESTARLE 1000,00€ POR EJERCICIO CONTABLE DE ACUERDO A SU DESGASTE POR EL USO. PARA TAL FIN SE CREÓ UNA "CUOTA AMORTIZATIVA". LA FRESADORA CONSIGUE VENDERSE AL CABO DE 8 AÑOS Y 3 MESES. ¿POR CUANTO SE HA VENDIDO LA FRESADORA? ¿DE CUÁNTO HA SIDO EL AHORRO EN AMORTIZACIÓN DE LA EMPRESA CON LA VENTA DEL ACTIVO?
8.- ¿CUÁL ES LA DIFERENCIA DE TEMPERATURA EXPRESADA EN 'GRADOS' O 'GRADOS BAJO CERO' ENTRE UN LOCAL CLIMATIZADO A 24 GRADOS CENTÍGRADOS, Y UNA CÁMARA REFRIGERADA DE 26 GRADOS CENTÍGRADOS BAJO CERO?
1. Inicializamos la variable con el identificador temperatura_local a la que asignamos el valor int 24.
2. Hacemos lo propio con una segunda variable, proporcionándole el valor -26, con el signo negativo para señalar que nos hayamos por debajo de los cero grados centígrados.
3. Si aplicamos esta expresión, el -(-26) se transforma en + y devuelve en 4. una solución errónea.5. Con esta otra expresión, obtenemos el mismo resultado que en la expresión anterior sólo que con signo negativo, proporcionando también en 6. una solución errónea.
¿Cómo resolverlo?
Pues acudiendo a una nueva función preconstruida de Python: abs(). La contracción "abs", del inglés, "absolute", es decir, "absoluto" traducido al castellano. Y eso es precisamente lo que nos ofrece: cualquier número (number) pasado como argumento de la función, nos será devuelto el número en cuestión sin tener en cuenta su signo, fuera este positivo o negativo.
7. Así podemos obtener un resultado ajustado ala especificación que se nos demandaba: "grados bajo cero". Recordemos que es un error decir "menos n grados bajo cero", donde n es un número racional cualquiera.
Existe, no obstante, otro método para obtener números positivos o negativos simplemente pasando a uno o al otro el valor inicial de la variable, tal y como podemos comprobar en el ejemplo siguiente:
Y con esto damos por terminado este capítulo, que ya es hora. Para darnos un pequeño respiro antes de pasar al siguiente, ¿qué tal si aprendemos un poquito más sobre nuestro IDLE? Venga, vamos allá.
T3. IDLE DE PYTHON 3.
LAS FUNCIONES ord() Y chr():
La función integrada ord() trabaja con un único argumento en base al charset (conjunto de caracteres con el que trabaja el código máquina) de ASCII, de manera que que cuando pasamos un carácter nos devuelve un número entero que le corresponde en el charset. Veamos unos ejemplos:
También podemos pasarle a la función caracteres Unicode, (\u****), y esperar que nos devuelva un nuevo entero. Veámoslo:
La función chr() por su parte, y de manera complementaria a ord(), nos devuelve el carácter que corresponde en Unicode al entero que le pasemos como argumento. Veámoslo:
Finalmente, para los que estemos interesados en conocer el zen de Python al que hacíamos breve referencia al comienzo de este apartado, tan sólo tenemos que teclear en nuestro IDLE la siguiente instrucción:
>>> import this
y ver el resultado. Eso sí, viene en inglés. Para los perezosos, aquí va:
y ver el resultado. Eso sí, viene en inglés. Para los perezosos, aquí va:
ZEN DE PYTHON |
RANITA EN UNA CHARCA EN PLENO CAMINO DE PASACOLA, QUE COMUNICA A TRAVÉS DE UN CAMINO REAL EL MUNICIPIO DE EL ROSARIO, EN EL NORTE DE TENERIFE, CON EL DE CANDELARIA, EN LA COSTA SUR DE LA ISLA. |
No hay comentarios:
Publicar un comentario