lunes, 28 de octubre de 2024

Lenguajes. Python.

Diccionarios


El último tipo de colección de datos en Python es el diccionario, estructura cuyos elementos o componentes son pares llave/valor que denominamos entrada.


La llave puede ser cualquier elemento hashable, esto es, un objeto cuyo valor no cambia a lo largo de toda la ejecución del programa, siendo un hash el valor que identifica dichos objetos. Además, la llave no puede estar duplicada. El valor puede ser de cualquier tipo y puede estar repetido. Esta estructura del diccionario nos permite un rápido acceso a los datos que contiene.

La sintaxis del diccionario es la siguiente: al igual que los conjuntos, {} para delimitar su inicio y fin, entradas (pares llave/valor) separadas por comas y elemento llave-valor separados por dos puntos. 

  • Podemos declarar un diccionario directamente:

alumnos={"1º":"Juan", "2º":"Luis", "3º":"Melisa"}

  • O bien mediante el constructor de clase dict

alumnos = dict() -> Diccionario vacío
alumnos= dict(Uno="Juan", Dos="Luis", Tercero="Melisa") -> los números no son identificadores válidos, por lo que no pueden usarse como claves. Por este motivo, esta fórmula es poco empleada.

Al contario que los conjuntos, sí es posible acceder a un elemento concreto de un diccionario. Para ello utilizaremos la referencia llave, de forma similar a cómo hacíamos con listas y tuplas. Por ejemplo, para acceder al elemento 2, solicitaremos...

print(alumnos["2º"]) -> Devuelve Luis.

En este caso, tal y como definimos el contenido del diccionario, no podemos solicitar alumnos[1], ya que 1 no es la llave, sino 2º. Ahí radica una de  las diferencias entre diccionarios y listas/tuplas. Incluso aunque nuestro diccionario se configure como alumnos={1:"Juan", 2:"Luis", 3:"Melisa"}, si solicitamos el alumno situado como primera entrada deberemos hacerlo utilizando la llave de esa entrada (print(alumnos[1])), no su índice (print(alumnos[0])), orden que nos dará error.

También es posible añadir un nuevo elemento a un diccionario existente mediante el uso de la siguiente expresión: NombreDiccionario[llave]=valor. Por ejemplo, si deseamos añadir un cuarto elemento a nuestro diccionario alumnos diremos...

alumnos["4º"]="Carmela"

... por lo que si solicitamos ver el contenido de alumnos (print(alumnos)) obtendremos {1: 'Juan', 2: 'Luis', 3: 'Melisa', '4º': 'Carmela'}.

Igual que en lo relativo a las variables y al resto de las colecciones de datos, aun son muchas las cosas por aprender respecto a los diccionarios, y las iremos viendo en entradas sucesivas, pero por el momento considero que es suficiente como presentación y primer acercamiento a los diccionarios y, por extensión, a las colecciones de datos, por lo que cierro aquí, provisionalmente, este conjunto de entradas dirigidas a su presentación y primer análisis.

Lenguajes. Python.

Variables numéricas y operadores algebraicos


También python cuenta con tipos numéricos y los operadores algebraicos básicos necesarios para realizar las principales operaciones. En esta entrada trataremos de ambos.


Respecto a los tipos numéricos, al contrario que PseInt, y OOo Basic, en Python, al no ser necesario declarar previamente las variables (declaración implícita), en la asignación de valores o datos a las variables, no son necesarios nombres específicos para identificar los tipos de variables, aunque procesos de conversión o cambio de tipo revela que se pueden diferenciar tres conjunto numéricos (lo que equivale a decir que se identifican tres tipos numéricos: entero (Int), reales do de coma flotante (float) e complejos (números con parte imaginaria). Siguiendo la lógica de la teoría de conjuntos, los reales incluyen a los enteros y los complejos a los reales.

NOTARecuerda el gráfico de los conjuntos numéricos. En él se muestran los conjuntos y las relaciones que inclusión que rigen su relación. Los número complejos (conjunto C) incluyen los reales (conjunto R) y los imaginarios, por lo que constituyen el grupo más amplio de todos los conjuntos numéricos descritos por la ciencia matemática. Si estás interesado en conocer qué son los números imaginarios y las operaciones que se pueden realizar con ellas, te recomiendo que consultes este documento. También te recomiendo esta página.

A parte de simplificar el proceso de creación de variables y asignación de datos, la declaración implícita, cuando se trabaja con tipos numéricos, presenta en Python la ventaja añadida de que no existe incompatibilidad de tipos, desbordamiento o imprecisión por truncamiento cuando asignamos a una tercera variable el resultados de operar con otras. Es el propio intérprete el que se encarga de gestionar estas cuestiones (tipado dinámico), lo que nos evita tener que estar pendientes de cuestiones como las que comentamos respeto a los tipo numéricos y los operadores algebraicos en OOo Basic.

Te muestro una ejemplificación de lo anterior en estas comprobaciones realizadas directamente en el intérprete de Python (PyShell):

var1 = 23 

var2 = 32

var1+var2

55
var1 = 23
var2 = 34.54
var1+var2
57.54 

var1=23
var2 = 33
var3 = var1 + var2
print(var3)
56
var1 = 23
var2 = 3567.980
var3 = var1 + var2
print(var3)
3590.98

Observa que las primeras comprobaciones se realizan directamente y las segundas mediante la asignación del resultado de la operación a una variable. En azul el resultado que devuelve el intérprete.

Por lo que se refiere a los operadores algebraicos, Python cuenta con el mismo repertorio básico que se identifican en PSeInt y en OOo Basic, aunque varían algunos de los símbolos:

  • Suma (+)
  • Resta (-)
  • Multiplicación (*)
  • Potenciación (**)
  • División real (/)
  • División entera (//)
  • Resto (%)
Respecto a las dos modalidades de división (real y  entera) observa el resultado de aplicar los operadores /, // y % en Python, primero directamente...

var1 = 389

var2 = 23

var1/var2
16.91304347826087
var1//var2
16
var1%var2
21

... y en segundo lugar, asignando el resultado de la división a una variable:

vDivR = var1/var2
print(vDivR)
16.91304347826087
vDivE = var1//var2
print(vDivE)
16
vResto = var1%var2
print(vResto)
21

Como puedes ver, el resultado es el mismo, sin que se observen las diferencias de resultados en función del tipo de operación y variable. Esto supone una ventaja evidente sobre OOo Basic, y sobre otros lenguajes mucho más rigurosos en el tratamiento de los tipos numéricos. Y todo ello gracias el tipado dinámico.

Además de los operadores anteriores, Python dispone de unos operadores especiales llamados operadores aumentados de asignación. Son los siguientes (uno por cada tipo de operador básico):

  • += Suma asignación
  • -= Resta asignación
  • *= Multiplicación asignación
  • **= Potenciación asignación
  • /= División real asignación
  • //= División entera asignación
  • %= Resto asignación
Estos signos son equivalentes a lo que en otros lenguajes se expresa como asignación de operación a variable: a = a + x (siendo a la variable y x un número cualquiera). Por ejemplo:

a += 3 (Python) equivale a a = a + 3  (OOo Basic)

El resultado es una simplificación de la escritura del código, aunque para entender mejor su lógica, es necesario recordar que la asignación se realiza de derecha a izquierda, no de izquierda a derecha, por lo que la lectura de de la instrucción es la siguiente: el valor x (3), sumado al valor previamente asignado a la variable ase asigna a la misma variable a. El resultado es que ahora a = a+3.

Del mismo modo debemos entender el resto de las operaciones. Reproduzco a continuación la comprobación de estas instrucciones de asignación realizadas en el pyshell:

var = 5
print(var)
5
var+=3
print(var)
8
var-=3
print(var)
5
var*=3
print(var)
15
var**=3
print(var)
3375
var/=4
print(var)
843.75
var//=2
print(var)
421.0

Antes de dar por concluida esta entrada, me gustaría avanzar un poco más en el conocimiento del IDLE de Python y en su uso, ya que así es posible crear materiales de mayor complejidad. En concreto quisiera hablar de la diferencia entre el intérprete (Shell o PyShell) y el editor de código.

NOTA: Pyshell es el intérprete interactivo de comandos o instrucciones del IDLE que proporciona Python en su instalación. El editor de código, como su nombre implica, es una herramienta simple de escritura de texto, pero plenamente funcional para crear script.

Como vimos en una entrada anterior y en esta misma, podemos escribir código directamente en el intérprete del IDLE, pero hacerlo nos crea una importante restricción: únicamente podemos comprobar el funcionamiento de instrucciones sucesivas; aunque permite guardar el código generado durante nuestra sesión de trabajo (extensión .py) el resultado no es operativo, ya que necesitamos eliminar el texto identificativo inicial y los resultados de la propia ejecución de los comandos e instrucciones.

Cuando nos interesa guardar nuestro script plenamente funcional o desarrollarlo previamente para probarlo después como un todo, es necesario utilizar un editor de texto. Podemos utilizar cualquier editor, como el propio bloc de notas de Windows, pero el IDLE de Python cuenta con una aplicación orientada a este fin. Para acceder a ella deberemos...

Seleccionar el menú File del Shell y seleccionar...

  • New File, si queremos crear un nuevo script, u...
  • Open, si queremos acceder a un script ya creado.

diferencia del intérprete, el editor permite escribir el script para que sea interpretado posteriormente; también permite guardarlo (con extensión .py) y ejecutarlo a posteriori cuantas veces queramos (desde el menú Run). En principio, la ejecución se realiza en el intérprete (PyShell).

Finalmente, antes de dar por concluida esta entrada, incorporaremos la nueva funcionalidad del IDLE de Python e inauguraremos la creación de script en este lenguaje, aunque sea un script un tanto especial y limitado. Para ello te dejo acceso al "script" Python que contiene el conjunto de las comprobaciones que realizamos a lo largo de esta sesión. 

NOTA: Recuerda que, además de acceder a él, tienes que descargarlo, guardarlo en una carpeta de tu elección y acceder a él desde el IDLE de Python. Ya sabes cómo activarlo.

Lenguajes. Python.

Colecciones de datos. Tipología


Además de con datos individuales (variables) también podemos trabajar con  colecciones de datos, lo que nos permite simplificar y acortar el código, mejorando la eficiencia del algoritmo. En Python disponemos de varios agrupamientos de datos. En esta entrada realizaremos un breve introducción al tema.




En Python podemos usar con propiedad el término "colecciones" de datos, así, en plural, ya que contamos con cuatro tipos diferentes de colecciones: listastuplasconjuntos y diccionarios

Una lista es una colección o conjunto ordenado de datos que puede contener elementos de diferente tipo. Es la forma más simple de agrupamiento y se identifica por el uso de corchetes como delimitador: lista1 = ["ordenador","teclado"]

Una tupla es un conjunto de datos de diferente tipo. En ella los datos están ordenados y son inmutables, características estas que la diferencian de la lista: una tupla no se puede modificar una vez creada. La tupla queda delimitada por paréntesis:: tupla1 = ("ordenador",123,"teclado")

Mientras que en listas y tuplas identificamos sus elementos mediante un índice, en los conjuntos los elementos no se asocian a un orden, por lo que no emplean índices para localizar en ellos un elemento determinado. También frente a listas y tuplas, en los conjuntos no se pueden repetir contenidos (no puede haber dos elementos iguales), lo que nos acerca a la idea de conjunto matemático. Los conjunto se identifican por el uso de llaves como delimitadores: conjunto1 {"ordenador",1,"teclado"}

Finalmente, un diccionario es una colección de datos asociados en parejas, compuestas por una clave y un valor. Las claves no pueden repetirse. En Python los diccionarios se identifican, al igual que los conjuntos, por el uso de llaves como delimitadores, pero se diferencian por el uso de claves (llave) se asocian al valor mediante el separador "dos puntos" (:): diccionario1 = {1:"ordenador", 2:1, 3:"teclado"}

Con los visto hasta ahora nos podemos hacer una idea de la diversidad tipológica de las colecciones en Python. Esto supone cierta complejidad, pero también versatilidad en la definición y en el manejo de las colecciones de datos

En entradas posteriores desarrollaremos cada una de estas colecciones.

Lenguajes. Python.

Cadenas f


En otra entrada pudimos ver un modo peculiar de escribir el contenido de una instrucción print()print(f"{self.nombre} se sienta cuando se lo ordeno (y quiere, claro)."). Se trata de la llamada cadena f, formato en uso desde la versión Python 3.6, que sustituye al método format(), y que, al igual que éste, permite utilizar directamente variables dentro de cadenas.


Pero antes de continuar es necesaria una aclaración: tanto format() como las cadenas f nos remiten a las variables alfanuméricas, y más concretamente a los string como objetos, instancias de una clase (la clase string), por lo que format() se considera método específico de esta clase, al igual que otros muchos, como upper() y lower()tittle() y otros muchos otros. Ahora no me voy a detener en ellos, pero te dejo acceso a esta página en la que puedes entrar en mas detalle sobre esos métodos y la forma en que se usan. También te recomiendo esta otra página, mucho más completa, en la que puedes encontrar información técnica sobre los string y esta otra relacionada con la anterior y más genérica aun, sobre la biblioteca estándar de Python.

Volviendo a las cadenas f y su uso para concatenar cadenas incluyendo variables, recuerda que ya en OOo Basic nos mostramos especialmente interesados en este tipo de operaciones, debido a que, por funciones, trabajamos con frecuencia con documentos y necesitamos métodos prácticos y funcionales para componer textos. Un ejemplo de ello es construir un documento-tipo y personalizarlo a partir de información contenida en variables. 

El procedimiento combinar correspondencia es una forma de abordarlo que ya hemos utilizado como solución en otras propuesta. También hemos utilizado procedimientos de construir textos mediante la unión de cadenas y variables en Python, pero no haciendo uso de las cadenas f, así que me parece de interés que nos detengamos brevemente en ellas para comprender su funcionamiento.

Las cadenas f permiten introducir variables dentro de cadenas, simplificando y sobre todo, clarificando procedimientos de mayor más comunes, pero menos eficiente. Veamos cómo proceder suponiendo la creación de un script que genera un texto personalizado a partir de un documento-base como los que generamos como docap mediante OOo Basic. Aunque me limitaré a un único párrafo (por no alargar innecesariamente la propuesta), utilizaré los dos procedimientos disponibles en Python (el ordinario de concatenación y las cadenas f) para comprobar la funcionalidad de ambos procedimientos.

El texto-base es el siguiente:

Observaciones: Este informe se realiza a demanda de la Dirección del centro (12/10/2022) por petición de  tutoría, formulada mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (10/10/2022).

Este texto, aunque no excesivamente, es suficientemente complejo para que resulte interesante explorar las opciones de concatenación de texto según lo formulado antes como propuesta: contiene el volumen suficiente de texto fijo y de texto variable (a tratar mediante variables), y supone un ejercicio de concatenación de variables tipo string.

Suponiendo las variables siguientes y sus valores asignados...

demandante = "la Dirección del centro"
fechaDemanda = "12/10/2022"
peticion = "tutoría"
fechaPeticion = "12/10/2022"
fechaInforEqDoc = "11/10/2022"

... la formulación mediante cadenas concatenadas es como sigue:


print("Observaciones: Este informe se realiza a demanda de ", 
demandante, "(", fechaDemanda,") por petición de ", peticion, "(", fechaPeticion, "), mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (",fechaInforEqDoc,")")

... mientras que usando cadenas f se construye del siguiente modo:


print(f"Observaciones: Este informe se realiza a demanda de {demandante}, ({fechaDemanda} ) por petición de {peticion} ({fechaPeticion}, mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA ({fechaInforEqDoc})")

En ambos casos el resultado es el mismo:

Observaciones: Este informe se realiza a demanda de la Dirección del centro, (12/10/2022 ) por petición de tutoría (12/10/2022, mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (11/10/2022)

... pero el uso de la cadena f permite que nos olvidemos del tedioso y confuso proceso de  abrir y cerrar comillas (que en la concatenación clásica identifico mediante la escritura en dos colores), fuente de errores, lo que hace que sea más sencillo y fluido escribir el texto final dentro de la función print().

Lenguajes. Python.

Variables alfanuméricas (II)

Me ha surgido la necesidad de escribir líneas de código complejas formadas por string también complejos así que me he visto obligado a buscar una solución para crear un código legible a la vez que una salida por consola igualmente legible. 


Dado que esta situación puede darse con cierta frecuencia al manejar textos y variables alfanuméricas de cierta longitud y complejidad, me para que aportar soluciones de este tipo no es perder el tiempo en minucias, así que vamos a ver como podemos resolver este tipo de situaciones.

En primer lugar, cuando escribimos el código podemos acabar generando líneas de una elevada longitud que resultan difíciles de leer. Poder acotarlas ayuda a la lectura (y comprensión) de código.

Las soluciones son dos (al menos): acortar cada línea en una orden independiente o acortar la línea mediante un procedimiento que no genere error al intérprete. Un ejemplo:

Supongamos que queremos escribir lo siguiente como cadena de texto: 

"Dime la figura sobre la que quieres calcular el área. Para ello utiliza el siguiente código: C -> Cuadrado, R -> Rectángulo, T -> Triángulo, C -> Círculo"

Podemos perfectamente dividir el texto en dos partes, la primera informativa mediante la función print():

print("Dime la figura sobre la que quieres calcular el área. Para ello utiliza el siguiente código:")

... y la segunda mediante un input(), asociada a una variable para que cumpla su función (según se deduce de la configuración de la instrucción):

respuesta = input("C -> Cuadrado, R -> Rectángulo, T -> Triángulo, C -> Círculo")

De este modo evitamos crear una línea excesivamente larga que dificulta la lectura del código, aunque puede que la primera exceda, aun así, los márgenes aceptables para un código legible. Si así fuera considerado, bien podría dividirse en al menos dos print() diferenciados, solucionando así el problema:

print("Dime la figura sobre la que quieres calcular el área.")
print("Para ello utiliza el siguiente código:")

En términos de legibilidad del código, la solución es perfectamente válida, pero nos crea un ligero problema, poco relevante aquí, pero no tanto en programas de muchas líneas y cadenas de texto largas: necesitamos dos o tres instrucciones para resolver el problema. Si esto lo es, también podemos recurrir a otra solución aceptable para el intérprete Python: utilizar como separador de líneas que mantiene la integridad de código como una unidad (una sola orden):

    respuesta=input("Dime la figura sobre la que quieres calcular el área"\
                "Para ello utiliza el siguiente código:"\
                "C -> Cuadrado"\
                "R -> Rectángulo"\
                "T -> Triángulo"\
                "C -> Círculo")

La estructura creada gana en legibilidad y elegancia a cista de multiplicar la concatenación de segmentos (cadenas), pero tiene un problema: la salida (output) por pantalla no resulta funcional. Digamos que trasladamos el problema de la legibilidad al output (del programa), lo que dificulta el input (para el usuario)

Dime la figura sobre la que quieres calcular el área Para ello utiliza el siguiente código: C -> Cuadrado R -> Rectángulo T -> Triángulo C -> Círculo

Este problema (al menos en parte) ya lo habíamos podido observar en la versión primera del input(), pero ahora se revela en toda su extensión y resulta claramente inadmisible. Afortunadamente tenemos una solución: utilizar un salto de línea incorporado a cada string (\n). Esta opción produce el efecto deseado en la salida del programa (el salto de línea) allí donde se ubica, con independencia de la posición que ocupe en el string que escribimos como código. En este caso nos interesa la coincidencia del fin y salto de la línea de código con el salto de línea del output (en pantalla), pero esto es circunstancial.

    respuesta=input("Dime la figura sobre la que quieres calcular el área"\
                "\nPara ello utiliza el siguiente código:"\
                "\nC -> Cuadrado"\
                "\nR -> Rectángulo"\
                "\nT -> Triángulo"\
                "\nC -> Círculo"\
                "\nInicial de la figura: ")
   
Lo importante es que la combinación de ambos recursos (\ para separar líneas sin romper la unidad de la instrucción, y "\nString..." para generar saltos de línea en pantalla) nos permiten obtener un código legible (como el de arriba), a la vez que una salida por pantalla igualmente legible con una única instrucción input()

Dime la figura sobre la que quieres calcular el área
Para ello utiliza el siguiente código:
C -> Cuadrado
R -> Rectángulo
T -> Triángulo
C -> Círculo
Inicial de la figura:

domingo, 27 de octubre de 2024

Python. Lenguaje.

Iteración. Bucles.

Literación no es otra cosa que la ejecución de una instrucción de forma repetida. Junto con  la sucesión lineal y la bifurcación condicional, la iteración es una de las formas que pueden presentar el desarrollo de un algoritmo. Los bucles son las instrucciones (o estructuras instruccionales) que concretan cómo hacerlo y la potencia de procesamiento de los ordenadores la que permite que se realice de forma rápida y eficiente.


Mediante los bucles podemos recorrer amplios conjunto de datos para encontrar los que deseemos, también podemos crear respuestas sucesivas en función de determinadas condiciones. En cualquier caso estamos hablando de dos cuestiones que se alejan del carácter básico que tiene como objetivo esta entrada (1), en la que me limitaré a exponer las estructuras de iteración.

El lenguaje Python cuenta con dos estructuras de iteración o bucles: el bucle for y el bucle while, que permiten dos formas diferentes de iteración (2): una (for, "para") mediante un iterador y la otra (while, "mientras") en función del cumplimiento de una condición. En esta entrada mostraré la forma básica de uso de ambos, dejando para posteriores una explicación más detallada de las mismas.

El bucle for cuenta con una variable, un objeto iterable y un bloque de código. Un iterable no es otra cosa que un conjunto de valores que va tomando la variable en cada paso de la ejecución del bucle. Son muchos los objetos iterables en Python, además de los que podemos construir nosotros (3).

Una forma básica de crear un iterable en Python es la siguiente...

for n in (1,2,3,4,5):

    print("El valor de n es",n) 

La variable n adopta sucesivamente los valores indicados en el iterable (1,2,3,4,5) al que se referencia (n in (1,2,3,4,5)). Todo ello se muestra (visualiza) gracias a la instrucción o bloque de código subordinado que sigue ( print("El valor de n es",n) ) y que es lo siguiente:

El valor de n es 1
El valor de n es 2
El valor de n es 3
El valor de n es 4
El valor de n es 5

Otra forma de expresar un bucle for es la siguiente (4):

num = 5

for n  in range(1,11):

    print(n,"x",num,'=',n*num) 

... que nos devuelve:

1 x 5 = 5
2 x 5 = 10
3 x 5 = 15
4 x 5 = 20
5 x 5 = 25
6 x 5 = 30
7 x 5 = 35
8 x 5 = 40
9 x 5 = 45
10 x 5 = 50

La función range() cuenta con tres parámetros o valores: el inicial, el final y el de incremento (opcional). Mediante range(1,11) obtenemos un objeto iterable formado por los valores 1, 2, 3, 4, 5, 6, 7, 8, 9 y 10, que son los que necesitamos para crear la tabla de num (en nuestro caso, del 5). Observa que si hiciéramos algo parecido mediante la primera formulación no obtendríamos ese resultado, ya que no se utiliza el valor num, únicamente se itera por los posibles valores de (5). La función range() simplifica la expresión del iterable, haciendo innecesaria la enumeración de sus contenidos concretos y permitiendo establecer series de mayor complejidad (mediante el valor de incremento)

Una tercera forma de iterar es partiendo de un objeto iterable previamente definido y utilizarlo en el bucle como tal (como iterable) que recorremos mediante una variable. Un ejemplo (6)...

dias = ['lunes','martes','miércoles','jueves']

for dia in dias:
    print(dia)

... que nos devuelve

lunes

martes

miércoles

jueves

El bucle while tiene otra lógica de funcionamiento, ya que se basa en el cumplimiento de una condición que previamente se debe establecer (7) y que es previsible que se modifique a lo largo del recorrido del bucle (8). Además de las instrucciones que se desarrollen en su interior, while puede contener una instrucción o cláusula else, cuya función es establecer las instrucciones que se cumplirán cuando la condición deje de ser V. Esta cláusula es opcional.

Veamos un ejemplo de bucle while:

num = 0

while num < 10:
    print (num)
    num = num + 1 
else:
    print ("Has llegado a la meta") 

En este script establecemos un valor de inicio para la variable num (num = 0), lo que permite que el el bucle se inicie sin generar error. A continuación establecemos la condición del bucle (while num < 10), esto es: este bucle se ejecutará mientras la condición num < 10 sea True. Mientras esa condición se cumpla, el bucle nos devolverá como salida la escritura del valor que toma num (esto es, se cumple la instrucción que contiene:  print (num)).

Para evitar un bucle infinito, en este caso hemos optado por incorporar una instrucción de tipo contador (num = num + 1) que modifica el contenido de la variable, con lo que, en un momento determinado, la condición de partida dejará de ser True para pasar a False. En ese momento entra en funcionamiento la cláusula else, por lo que la salida final de bucle será el contenido de la instrucción asociada a else (print ("Has llegado a la meta")).

Otra forma muy común de trabajar con el bucle while consiste en establecer una variable de control del bucle con valor inicial True, que será la condición de ejecución del propio bucle. Dentro del bucle realizaremos alguna comprobación con un condicional que servirá para modificar el valor de la variable de control y finalizar la ejecución del bucle, al dejar de cumplirse la condición en que se basa.

print('Escribe un número par') # Un número impar servirá para terminar el bucle
seguir=True
while seguir:
    numero=input('Número: ')
    numero=eval(numero)
    if numero%2==1:
        seguir=False
else:
    print('Ha finalizado el bucle.', numero, 'es impar')

En este caso, el cambio de la condición (que quedó definida expresa y previamente en la variable booleana seguir) es el resultado del cumplimiento de una condición establecida dentro del bucle mediante una estructura condicional (if numero%2==1) coherente con el contenido del bucle (las instrucciones que desarrolla ( numero=input('Número: ') -> numero=eval(numero)). Nótese que la instrucción else pertenece al bucle while, no al condicional if (9)

Son muchas las cosas que tenemos que aprender sobre los bucles y sus usos, pero de momento disponemos ya del conocimiento suficiente para integrarlos en sencillos script de aprendizaje, alguno de ellos, incluso, con cierta funcionalidad práctica; aunque esta no sea, por el momento, nuestro objetivo.
NOTAS

(1) Lo expresado remite a las colecciones de datos (matrices) y al uso combinado de bucles y condicionales, temas que se abordarán más adelante.
(2) Tema este también de suficiente complejidad como para requerir un abordaje específico que no corresponde realizar ahora.
(3) Me refiero a las listas, las cadenas de texto, las tuplas... Sobre todas ellas, como iterables, hablaremos en su momento, aunque, por motivos didácticos, utilizaremos ahora algunas de ellas en la ejemplificación del funcionamiento de la iteración. 
(4) Código básico de la tabla de multiplicar del 5.
(5) En el segundo ejemplo, esa iteración de n por el range() queda expresada en el primer valor de lo que devuelve print(). Para replicar el mismo objetivo deberíamos crear el siguiente script:
num = 4
for n in (1,2,3,4,5,6,7,8,9,10):
    print (n,'x',num,'=',n*num)
(6) Que supera los objetivos de esta entrada y que explicaremos en otro momento.
(7) Esta condición determina el desarrollo del bucle, ya que éste sucede mientras se mantenga la condición original, esto es, hasta que esta deje de ser True (V).
(8) En caso contrario daría lugar a un bucle infinito, situación que, obviamente, deberemos evitar.
(9) En función del nivel de sangrado o indentación, que la ubica a la altura de while, no de if. En caso de encontrarse a la altura de if pertenecería a ese condicional y no al bucle. Véase la importancia de la indentación en Python y de lo necesario que es ejecutarla correctamente.

Python. Lenguaje.

Condicionales en Python


Lbifurcación es un componente fundamental de cualquier programa, por simple que éste sea. Obedece a la opcionalidad que resulta de los propios datos y del desarrollo lógico del algoritmo. Algo tan simple como la correcta identificación del género o número gramaticales es, para un algoritmo, una cuestión de bifurcación. La bifurcación se resuelve, en términos de lenguaje de programación, con estructuras condicionales. 


El lenguaje Python cuenta con una única estructura condicional con tres niveles de complejidad. Esta estructura es análoga al Il-ElseIf-Else de OOo Basic, aunque con presenta características propias. Estas son:
  • En Python el condicional (al igual que el resto de las instrucciones) se escribe en minúsculas.
  • No existe sentencia de finalización, usando como alternativa del identificador del bloque condicional el indentado (sangrado) del código, que es obligatorio en Python, aunque  también recomendable en el resto de los lenguajes.
  • La instrucción ElseIf se simplifica como expresión y se expresa como elif.
  • Al finalizar cada una de las instrucciones se deben escribir dos puntos (:)
El funcionamiento del condicional es el mismo que describimos en OOo Basic:
  • Se usa únicamente if cuando no existe o no nos interesa más que comprobar si la proposición cumple la condición que nos interesa.
  • Se emplea también else cuando, además de esa condición, nos interesa controlar su alternativa.
  • Y se emplea elif cuando existen varias condiciones posibles para la misma proposición.

Vamos a trasladar el código OOo Basic a código Python para mostrar similitudes y diferencias:

En OOo Basic:

If vEdad > 17 Then
     MsgBox "Eres mayor de edad"
End If 

En Python

      Print("Eres mayor de edad") 
Esta es la formulación más simple de un condicional y nos permite apreciar tres diferencias básicas, que muestran las características de la sintaxis de Python:
  • La primera, el sangrado (o indentado), obligatorio en Python nos muestra dos niveles: el primero, el de la sentencia if, y el segundo, el del bloque de código (en este caso una única sentencia print())
  • La segunda, la ausencia de Then y sentencias similares, y su sustitución por (:). Muy importante no olvidar estos dos puntos.
  • Y la tercera, la ausencia de sentencia de finalización (End If), sustituida por el fin del sangrado.
Si queremos controlar el caso en que no se cumpla esta condición, esto es, cuando la proposición vEdad >17 sea F, emplearemos la sentencia else.
    print("Eres mayor de edad")
Observa el modo en que se emplea else, qué posición ocupa respecto a if (a su misma altura), el uso de : al finalizar la sentencia y el mantenimiento del sangrado en la sentencia asociada.

Cuando queremos crear una estructura condicional anidada (un condicional dentro de otro condicional), debemos mantener la jerarquía que implica este anidamiento mediante el incremento del sangrado, como puedes observar en este tercer ejemplo:

 
Fíjate en la posición que ocupa el segundo if respecto al primero: se sitúa a la misma altura que las sentencias print() del if primario, mientras que sus propias sentencias print() se desplazan (se sangran) hacia la derecha..

La simplicidad de Python en cuanto a estructura hace que sea muy exigente con el uso del sangrado, lo que genera sus dificultades a la hora de escribir estructuras condicionales anidadas complejas. Por ellos muchos programas de escritura de código suelen generar automáticamente estos sangrados, evitando así errores de "indentación".

Por último, dado que Python con cuenta con otra estructura condicional, sólo disponemos de la instrucción elif para construir condicionales múltiples que en otros lenguajes se pueden resolver mediante estructuras Select Case. Reproduzco a continuación el script sobre días de la semana creado en PSeInt (pseudocódigo) junto con su formulación en Python para que puedas comparar semejanzas y diferencias.

  Dado que el resto ya es conocido, sólo pedirte que te fijes en la sintaxis de elif:
  • En cuanto a sangrado, se escribe a la misma altura que if.
  • Dado que es una valoración diferente de la proposición (en este caso empleando el operador de igualdad, ==), escribimos los términos de la comparación (variable [operador relacional] valor)
  • La línea elif también finaliza con dos puntos (:)
  • La instrucción o instrucciones que sigue a elif deben sangrase un nivel (un tabulador, cuatro espacios), igual que las que siguen a if o a else.
Ahora ya dispones del nivel de conocimientos suficiente para desarrollar algoritmos que impliquen el uso de la condicionalidad y den respuesta a las necesidades de bifurcación de la respuesta en función del las condiciones que se observen en los datos. Desde la opción de inicio de un test en función de la edad del niño, hasta la toma de decisiones sobre categorización NEAE en función de casuística y datos empíricos, pasando por la simple personalización de un texto en función del tratamiento gramatical masculino vs. femenino... lo que necesites. 

sábado, 26 de octubre de 2024

Python. Lenguaje

Funciones de conversión de variables


Dado que la función input() se asocia necesariamente a una variable de tipo string, necesitamos contar con una función que nos permita cambiar de tipo a esa variable. No es esta la única circunstancia en que necesitaremos utiliza este tipo de funciones, pero sí una de las más evidentes. Trataremos en esta entrada sobre las funciones de conversión y su uso.


De momento, en esta fase introductoria de nuestro aprendizaje de Python, vamos a conocer cuatro funciones de conversión básicas. Siendo v la variable a convertir...
  • str(v) -> Transforma v en una variable de tipo cadena (string)
  • int(v) -> Convierte en una variable numérica de tipo entero (integer)
  • float(v) - > Convierte v en una variable numérica de tipo decimal (float)
  • eval(v) -> Permite que contenga cualquier expresión válida en Python.   
Veremos a continuación algunas aplicaciones prácticas (1) para entender mejor la importancia de realizar estas conversiones, el modo de usar estas funciones y los resultados que obtendremos con ellas.

#Primer script Python.
#Incluye el uso de variables, operadores y funciones input y output

print ("Bienvenido a este mi primer programa Python")
print("Voy a hacerte alguns preguntas y al final te daré una respuesta",'\n')
nombre = input("Dime tu nombre: ")
pueblo = input("Dime el lugar donde naciste: ")
ano_nac = input("Tu año de nacimiento: ")
ano_act = 2024
ano_nac = int(ano_nac)
annos = ano_act - ano_nac
annos = str(annos)
print(nombre,"naciste en",pueblo,"en el año",str(ano_nac),"y ahora tienes",annos,"años")

En este primer caso realizo la conversión de una variable, cuyo valor se solicita al usuario mediante input(), esta conversión es de string a integer (ano_nac = int(ano_nac)) para poder realizar la operación (annos = ano_act - ano_nac). A continuación con el resultado de esa operación realizo la conversión inversa para poder utilizarla en la salida (print(nombre,"naciste en",pueblo,"en el año",str(ano_nac),"y ahora tienes",annos,"años")). Podría haberlo hecho directamente en el mismo print(), como en el caso de la variable ano_nac (str(ano_nac)). 

En este caso, el único cambio de tipo necesario es el primero (ano_nac = int(ano_nac)), ya que provoca error usar variables string con operadores algebraicos, pero no los otros dos, ya que el intérprete asume esas variables numéricas como parte de la cadena que se devuelve el programa.

Veamos un segundo ejemplo, en este caso de operaciones matemáticas.

opera1 = 35
opera2 = input("Segundo operador numérico: ")
resulta1 = opera1 + opera2

Este script produce error por tratar de sumar una variable string (opera2 = input("Segundo operador numérico: ")) con una integer (opera1 = 35); para evitarlo es necesario convertir opera2 en integer.  Esta es una de las formas posibles (resulta1 = opera1 + int(opera2)), pero si queremos volver a utilizarla en una segunda operación resulta que sigue siendo una variable string, por lo que seguirá dando el error inicial (2), así que la mejor opción es convertirla en integer antes de operar (opera2=int(opera2)) (3)

Si en vez de sumar queremos realizar una división (resulta2 = opera1 / opera2) nos devolverá un valor float, ya que resulta2 asume como tipo el resultante de la operación, no limitando este tipo al de los valores de los operandos, por lo que no se produce ni error ni encubrimiento (4).

Tras las modificaciones, este sería el script resultante:

# Segundo script Python
# Operaciones aritméticas y funciones de cambio de tipo de variable 
opera1 = 35
opera2 = input("Segundo operador numérico: ")
resulta1 = opera1 + int(opera2)
print(resulta1)
opera3 = int(opera2)
resulta2 = opera1 / opera3
print(resulta2)


NOTAS

(1) Desarrolladas desde el generador de script del IDLE y obtenemos los resultados en el Shell.
(2) Esto es así porque lo que hacemos mediante esa primera fórmula no es convertir opera2 en integer, si no usar una versión integer de una variable string en una operación cuyo resultado se asigna a una tercera variable (resulta1). Realmente opera2 sigue siendo la variable string que deriva del uso de la función input(). Esta forma de operar también tiene su ventaja: conservar el dato original de la variable.
(3) Ahora opera2 queda convertida en una variable integer, dada la reutilización que hacemos de ella y el uso de la función int().
(4) Por encubrimiento (de tipo) me refiero a que devolviera un valor entero por asimilación al tipo integer. Esto generaría problemas en cálculos en los que los valores decimales son importantes. Pero aquí no es el caso. Tampoco se produciría en el caso de que resulta2 hubiera sido "declarada" previamente como integer, ya que al usarla en la operación se produce una reasignación de contenido y un cambio de tipo de variable (en este caso, de integer a float) por el tipado dinámico, que es una de las características de este lenguaje.