lunes, 28 de octubre de 2024

Lenguajes. Python.

Listas. Manejo básico.

Dado que las listas son las colecciones de datos más simples con que cuenta Python. y que en la [entrada anterior] nos limitamos a presentar y diferenciar las distintas colecciones de datos en este lenguaje, pero no dijimos nada sobre formas de trabajo con ellas, a fin de lograr nuestro objetivo de dar funcionalidad al aprendizaje desde sus inicios, parece necesario que dediquemos esta entrada a aprender cómo se trabaja con las listas, a fin de que podamos aplicar estos conocimientos básicos en ejemplos y ejercicios, pero también al desarrollo de proyectos elementales pero ya de cierta funcionalidad.


Como decíamos en su presentación, una entrada anterior, las colecciones de datos nos permiten almacenar un conjunto de datos asociados a una única referencia, mientras que con una variable únicamente podemos acceder a un dato concreto. Python cuenta con cuatro tipos de colecciones de datos, siendo la lista la más simple y posiblemente también la más flexible de ellas.

Una lista es un conjunto ordenado de datos de diferente tipo (caracteres, cadenas, enteros, reales, booleanos) que pueden estar repetidos. Estas características, junto con las operaciones permitidas sobre ella, la convierten en un recurso muy flexible para el almacenamiento de datos.

La forma de declarar una lista es tan simple como se muestra en el ejemplo siguiente:

vListaDiasSemana = ["lunes","martes","miércoles","jueves","viernes"]

  • Se declara y asigna contenido de la misma forma y con el mismo operador que una variable, unificando ambos procesos en una única sentencia.
  • El identificador de la lista es su delimitador: los corchetes.
  • Los elementos o datos se separan mediante comas.
  • Aunque en ésta todos los elementos son del mismo tipo, no es esta una restricción aplicable a las listas en Python.
  • Aunque podemos escribir la lista sin más, para poder acceder a ella o a alguno de sus elementos, es necesario asignarla a una variable (vListaDiasSemana)
  • Las listas pueden contener 0 elementos o todos los que deseemos.
Es importante entender que cada elemento de la lista ocupa una posición dentro de ella y que esta posición o índice es el que nos permite acceder a cada uno de los contenidos en la lista, de forma similar a cómo accedemos al contenido de una variable, aunque respetando su propia sintaxis. Si para acceder al contenido de una variable únicamente tenemos que referenciarla, para acceder a un elemento determinado de una lista, debemos hacerlo especificando su índice. Si no indicamos ese índice se supone que estamos accediendo a toda la lista:
 
vPalabra = "casa"
vlstPalabras = ["casa","mesa","armario"]
print(vPalabra) -> devuelve casa
print(vlstPalabras[0]) -> devuelve casa
print(vlstPalabras) -> devuelve ['casa','mesa','armario']

  • Si la lista vlstPalabras estuviera vacía, print(vlstPalabras[0]) provocaría un error (no hay elemento vlstPalabras[0]), no así print(vlstPalabras) -> devuelve [].
Podemos conocer el número de elementos de una lista mediante la función len(), cuyo resultado (return) podemos informar directamente mediante print(), o asignar a una variable para su posterior tratamiento. Por ejemplo, en vListaDiasSemana:

print(len(vListaDiasSemana))                    -> Devuelve 5
vNumDiasSemana=len(vListaDiasSemana)
print(vNumDiasSemana)                            -> Devuelve 5

Una lista es modificable: podemos cambiar su contenido, añadir elementos o borrarlos, todo ello de forma muy simple:
  • Para cambiar un elemento, únicamente tenemos de reasignarle nuevo contenido haciendo uso de su índice; por ejemplo, siendo la lista...
vlstPalabras = ["casa","mesa","armario"]

 ... si queremos cambiar vlstPalabras[0] "casa" por "cama" diremos...

vlstPalabras[0] = "cama"

  • Para añadir un nuevo elemento a una lista utilizaremos la siguiente expresión (el nuevo elemento se añade al final de la lista):

 vlstPalabras = vlstPalabras + ["mesita"]

  • Para borrar un elemento de la lista (la anterior, por seguir con el ejemplo) usaremos la instrucción del de siguiente modo:

del vlstPalabras[2] -> Borra el elemento "armario" que ocupa la tercera posición. 

Podemos trabajar con varias listas, por ejemplo dos, y unirlas en una tercera. Supongamos dos listas:

vlstMuebles1=["mesa","silla","taburete"]
vlstMuebles2=["sofá","armario","mesita"]

... la unión de ambas mediante la instrucción...

vlstMuebles= vlstMuebles1+vlstMuebles2

... nos da como resultado... 

print(vlstMuebles) -> Devuelve ['mesa', 'silla', 'taburete', 'sofá', 'armario', 'mesita']

Además de unir dos listas en una tercera, también podemos considerar otras opciones, ya que una lista puede estar formada por una serie de elementos/datos (lista simple), pero también por una combinación de elementos y listas o por una colección de listas. La primera formulación ya la conocemos, tanto en su presentación más sencilla, como resultado de la unión o suma de dos listas; veremos a continuación las otras dos.

  • Lista resultante de la unión de una lista con otra mediante inclusión. Sea la lista inicial vlstMuebles1=["mesa","armario"] y queremos modificarla para que esté conformada por la estructura de contenidos Muebles + Muebles de asiento; para ello creamos una segunda lista con muebles de asiento (vlstAsientos=["silla","taburete","sillón","tresillo"]) y la incorporamos como elementos de la lista original:

vlstMuebles=["mesa","armario",vlstAsientos]

... obteniendo como resultado

print(vlstMuebles) -> Devuelve ['mesa', 'armario', ['silla', 'taburete', 'sillón', 'tresillo']]

Obsérvese que lo que alteramos es la estructura de la primera lista, no unimos ambas; de ahí que los elementos de la segunda lista (que ocupa como elemento de la primera la posición 3 (vlstMuebles[2]), aparecen delimitados como lista mediante [ ]. Esto es importante entenderlo, ya que el acceso a los contenidos de esta lista anidada se rigen por su doble posicionamiento: como elementos [2] de la lista principal y como elementos [x] de la lista secundaria. Así, si solicitamos el contenido de la posición [2], obtenemos...

 print(vlstMuebles[2]) -> Devuelve ['silla', 'taburete', 'sillón', 'tresillo']

... por lo que si lo que deseamos es obtener el contenido de la posición 2 de la lista anidada (taburete), deberemos referenciarlo indicando ambos índice: el primero como elemento de la lista principal y el segundo de la lista anidada:

print(vlstMuebles[2][1]) -> Devuelve taburete

  • Un procedimiento similar se sigue para construir una lista formada por listas (lista de listas). Por ejemplo, supongamos que tenemos un conjunto de listas cuyos elementos representan subconjuntos de un conjunto principal y queremos representar esa pertenencia transformado el conjunto principal en una lista de listas, cuyos elementos son esos subconjuntos. 

lstFrutas=["pera","manzana","plátano"]
lstLegumbres=["garbanzo","lenteja","haba"]
lstHortalizas=["zanahoria","tomate","pimiento"]
lstVegetales=[lstFrutas,lstLegumbres,lstHortalizas]
print(lstVegetales) -> Devuelve [['pera', 'manzana', 'plátano'], ['garbanzo', 'lenteja', 'haba'], ['zanahoria', 'tomate', 'pimiento']]

El acceso a un elemento cualquiera de cualquiera de estas tres listas sigue el procedimiento explicado antes. Por ejemplo, para acceder al elemento 2  ([1]) de la lista 3 ([2]), se realiza con las siguiente instrucción:

 print(lstVegetales[2][1]) -> Devuelve tomate

El uso de bucles es una estrategia muy frecuente para recorrer los elementos de una lista y permite desarrollar procesos muy interesantes en la construcción de algoritmos. Esto es debido a la posibilidad de combinar el uso de las variables contador en combinación con los índices de las listas. Veamos un ejemplo sencillo: 

Supongamos una lista que contiene los nombres de los alumnos, una segunda que contiene sus apellidos y una tercera que contiene las calificaciones en una prueba.

lstNombre=["Julián","Pedro","Matilde", "Ana"]
lstApellidos=["Alonso Pérez","González López","Ramírez De Luis","Ordóñez Núñez"]
lstNotas=[8,9,7,4]
for i in range(4):
    print(lstNombre[i])
    print(lstApellidos[i])
    print(lstNotas[i])

Devuelve
Julián
Alonso Pérez
8
Pedro
González López
9
Matilde
Ramírez De Luis
7
Ana
Ordóñez Núñez
4

Pero en Python también podemos trabajar con el bucle For directamente sobre una lista, lo que simplifica enormemente la formulación de estas estructuras. Un ejemplo sobre una de las listas anteriores. Para ello es suficiente con emplear la expresión for item in NombreLista

lstNombre=["Julián","Pedro","Matilde", "Ana"]
for item in lstNombre:
print(item,end=" ") -> Devuelve sucesivamente Julián  Pedro  Matilde  Ana

Una expresión similar a la anterior es la que usaremos para saber si un dato concreto forma parte de una lista. Sobre la lista anterior (lstNombre=["Julián","Pedro","Matilde", "Ana"]), para saber  si el Carlos forma parte de la lista formularemos la siguiente instrucción: "Carlos " in lstNombre. Esta expresión devuelve un booleano (en este caso False, ya que Carlos no forma parte de lstNombre).

Podemos asociar esta búsqueda a un condicional y en función del resultado generar una bifurcación del algoritmo o, más sencillo, añadir el elemento a la lista de nombres. Para ello primero deberemos asignar el resultado de "Carlos " in lstNombre a una variable:

vBoolA = "Carlos" in lstNombre
if vBoolA==False:
    lstNombre=lstNombre+["Carlos"]
print(lstNombre) -> Devuelve ['Julián', 'Pedro', 'Matilde', 'Ana', 'Carlos']

Mucho es aun lo que falta por aprender sobre las listas y su manejo, pero con lo visto ya hemos aprendido lo suficiente para incluirlas en nuestros ejercicios y proyectos.

Lenguajes. Python.

Colecciones de datos. Tipología.

Además de con los datos individuales (variables) también podemos trabajar con  colecciones de datos, lo que nos permite agruparlos y mejorar la eficiencia del algoritmo. En Python disponemos de varios agrupamientos de datos. En esta entrada realizaremos un breve introducción sobre esta cuestión.


Concretando lo anterior en Python se emplea con propiedad el término "colecciones de datos" ya que este lenguaje cuenta con cuatro tipos diferentes: 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",1,"teclado"]

Una tupla es un conjunto de datos de diferente tipo; 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 (e identificada) por paréntesis:: tupla1 = ("ordenador",1,"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, que implica cierta complejidad, pero también versatilidad en la definición y el  manejo de las colecciones de datos

En entradas posteriores desarrollaremos cada una de estas colecciones, pero ahora ya disponemos de información suficiente para empezar a utilizarlas en script simples; lo que constituye nuestro objetivo en estos momentos.

domingo, 27 de octubre de 2024

Lenguajes. Python.

Creación y acceso a archivos.

Hasta este momento todo lo que hemos podido hacer desde Python ha sido efímero, perdiéndose los resultados por carecer de medios para almacenarlos. Tampoco hemos podido acceder a datos externos, salvo lo que introduce el usuario mediante la función input(). Para evitar esto e incrementar la funcionalidad de nuestros primeros script (1) necesitamos aprender a escribir archivos externos que se puedan almacenar y también a acceder a ellos y a su contenido. Al menos lo primero es fundamental para que no se pierda el resultado de nuestro trabajo. 


Empezaremos por aprender los comandos básicos de manejo de ficheros, que se reducen a cuatro, dos para especificar el tipo de fichero (texto o binario) y uno complementario que comprende los dos modos principales  de trabajo: la lectura y la escritura de los archivos.
  • "r(read) es la opción que utiliza Python por defecto (si no se especifica nada) y nos permite abrir un fichero para lectura, pero da error si este fichero no existe, por lo que tendremos que saber de antemano que el fichero existe. Un ejemplo de uso es la presentación de un texto explicativo sobre el objetivo del algoritmo y su manejo. De este modo liberamos el algoritmo de información complementaria y podemos modificar ésta sin necesidad de modificar el propio algoritmo.
  • "w" (write) abre un fichero para escritura borrando la información que pudiera contener. Si el fichero no existe, lo crea, por lo que es útil para crear nuevos archivos y cuando trabajamos con archivos externos que interesa modificar sin acumular versiones diferentes del mismo.
  • "x" (create) crea un fichero para escribir en él. Si el fichero ya existe devuelve error, por lo que, al contrario que con "r", necesitamos saber que el fichero no existe. Es útil para generar nuevos archivos externos en los que guardar la información generada por el script, siempre y cuando sea necesario crear nuevos ficheros en cada proceso.
  • "a" (append) abre un fichero ya creado para escribir en él situando el cursor al final de su contenido, por lo que no se altera el contenido previo. Esto hace que sea útil cuando queremos añadir la información a la previamente guardada (incluyendo la generada por script diferentes al actual).
Los dos comandos relativos al tipo de contenido (texto o binario) son los siguientes:
  • "b" (binary) abre el fichero en modo binario (valores 0-1 en lugar de texto plano); ficheros como fotografías, archivos ejecutables, ficheros de LO-Writer o MO-Word, por ejemplo. 
  • "t" (text-mode) abre el fichero en modo texto plano.
Finalmente el signo "+" abre el archivo en modo lectura y escritura simultáneamente.

El modo de acceder/crear un fichero pasa por definir una variable (ej fichero) y asignar a ella...
  • la función de apertura: open()
  • el directorio y nombre del fichero: open("./NombreFichero.txt")
  • el modo de acceso: open("./NombreFichero.txt", "rt")
  • y la codificación:  open("./NombreFichero.txt", "rt", encoding="utf-8")
Obtendremos con resultado la instrucción fichero =  open("./NombreFichero.txt", "rt", encoding="utf-8") siempre que nuestro objetivo sea abrir en modo texto un fichero llamado NombreFichero.text, ubicado en el mismo directorio en que se encuentra el archivo Python desde el que se llama al citado archivo (2) empleando la codificación utf-8, que permite el reconocimiento de los caracteres propios del idioma (ñ, tildes...) (3)

Una vez abierto el fichero de tipo texto plano (existente en el directorio indicado) en modo lectura, asignamos el resultado de la función de lectura de su  contenido (fichero.read()) a una variable (texto=fichero.read()) y (por ejemplo) posteriormente imprimimos en pantalla el contenido asignando a la dirección de memoria que se identifica con dicha variable (print(texto)). Finalmente cerramos el acceso al fichero mediante la función close()fichero.close().

En el archivo ficheros1.py te dejo lo anteriormente explicado junto con otros cuatro script que se explican mediante comentarios. Cada uno de ellos realiza una función diferente, aunque similar, por lo que te da idea de las opciones disponibles en cuanto a la lectura de archivos. Estos script están comentados, por lo que no están activos. Deberás eliminar esos comentarios para probar su funcionamiento. También te dejo acceso al archivo .txt utilizado en esta práctica, aunque puedes sustituirlo por el que tu prefieras siempre que mantengas el nombre actual o modifiques el nombre del archivo en los script.

#Lectura de ficheros de texto con Python

#Apertura, lectura y cierre de un fichero existente
print("Lectura de archivo completo -------------")
fichero=open('./prueba.txt','rt',encoding="utf-8"))
texto=fichero.read()
print(texto)
fichero.close()
#Apertura y lectura de un fichero línea a línea
print("Lectura del archivo línea a línea -----------------")
for linea in open("prueba.txt","rt",encoding="utf-8")):
    print(linea)
#Lectura línea a línea con readline()
print("Lectura de la primera línea del archivo ----------------")
fichero=open("prueba.txt","rt",encoding="utf-8"))
print(fichero.readline())
fichero.close
"""
#Lectura línea a línea mediante readlines()
"""
print("Lectura de las líneas como elementos de lista ----------------")
fichero=open("prueba.txt","rt",encoding="utf-8"))
lineas=fichero.readlines()
fichero.close()
print(lineas[1])
print(lineas[3])
#Lectura mediante bucle con función list()
print("Lectura de las líneas mediante bucle y list() -----------------------")
fichero=open("prueba.txt","r",encoding="utf-8"))
lineas=list(fichero)
fichero.close()
for item in lineas:
    print(item)
#Mantenimiento de script en pantalla
print("Pulsa INTRO para finalizar")
input()


Para el correcto funcionamiento del conjunto, deberás incluir ambos archivos (.py y .txt) dentro de una carpeta o subdirectorio creado en tu escritorio (4).

NOTAS

(1) Y en buena lógica, empezar a pensar en crear algo de utilidad práctica. Por suerte, y aunque sea aun de forma muy limitada, no nos falta mucho para obtener resultados prácticos con Python.
(2) En este caso estaríamos definiendo una ruta relativa, que también admite como dirección o ruta NombreFichero.txt. Si deseáramos utilizar una ruta absoluta deberíamos escribirla completa, por ejemplo, C:\Users\NombreUsuario\Desktop\BLOG\ORIENTACIONyPROGRAMACION\python\NombreFichero.txt
(3) La expresión encoding="utf-8" puede dar error, además de ser innecesaria, según comprobación propia en Windows10 sobre archivo creado con Bloc de notas e intérprete Python 3.10.0. En ese caso (del que no he encontrado explicación) prueba eliminando encoding="utf-8".
(4) La ubicación propuesta es orientativa, ya que siempre que ambos estén ubicados en la misma carpeta, cualquier otra opción será válida dado que en los script se usan rutas relativas.

Lenguajes. Python.

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.

Lenguajes. Python.

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

Lenguajes. Python.

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.