×
Preliminares
1 Primeros pasos
  1.1 El intérprete interactivo
    1.1.1 Valores numéricos
    1.1.2 Operadores aritméticos
    1.1.3 Precedencia de los operadores
    1.1.4 Operadores de comparación
           y valores lógicos o booleanos

    1.1.5 La función type(),
           conversiones entre tipos

    1.1.6 Valores de texto
    1.1.7 Variables. Sentencias de asignación
    1.1.8 Más datos de tipo secuencia:
           Tuplas y listas

    1.1.9 RESUMEN
  1.2 El modo de edición de programas
    1.2.1 El flujo del programa.
           Sentencias condicionales

    1.2.2 Operadores lógicos
    1.2.3 Bucles
    1.2.4 Funciones
    1.2.5 Módulos
      keyword
      math
      random
      unicodedata
      time
      colorama
    1.2.6 RESUMEN
2 El mundo desde un ordenador
3 Ampliando horizontes
4 Teoría y teoremas
5 Jugando con Python

Aprender Python:

1 Primeros pasos

Dentro de los lenguajes de programación hay dos grandes grupos que son los lenguajes compilados y los lenguajes interpretados. Los primeros necesitan ser convertidos en código ejecutable a partir del código fuente, que es un texto con las instrucciones según la sintaxis y las reglas del lenguaje en cuestión. Esta conversión (que se llama compilación) produce ficheros ejecutables, que dependen fundamentalmente de sí mismos. Los segundos necesitan la presencia del intérprete que lee cada línea de instrucciones del código fuente y las ejecuta realizando aquello para lo que fueron diseñadas. Un lenguaje interpretado permite algo que no puede hacerse con uno compilado, que es la ejecución directa de instrucciones según se van tecleando línea a línea.

1.1 El intérprete interactivo

Siendo Python un lenguaje interpretado, nos da una excelente posibilidad para aprender y comprobar el código que es el intérprete interactivo. Cuando iniciamos IDLE, el entorno de desarrollo que viene incluído con la instalación de Python, aparecemos directamente en el modo interactivo. Nos daremos cuenta porque la ventana muestra el indicador (prompt):

>>> ▎

En este momento podemos empezar a teclear nuestras órdenes.

1.1.1 Valores numéricos

Los ordenadores son básicamente máquinas que manejan datos, y fundamentalmente números, así que lo primero que introduciremos serán valores numéricos. Si tecleamos, por ejemplo, 10 el intérprete mostrará esta salida:

>>> 10
10

Como podemos comprobar, la salida se limita a repetir el valor que hemos introducido. Esto no resulta particularmente útil, pero puede ser instructivo. Veamos un par de ejemplos más:

>>> 10
10
>>> -10
-10

Los valores que no tienen parte decimal son números enteros (int por integer) y pueden tener signo positivo o negativo. Por supuesto también podemos utilizar números con decimales.

>>> 10.5
10.5
>>> 10.
10.0
>>> 5.10
5.10
>>> .10
0.1

Los valores que tienen una parte decimal son números reales, en punto flotante por la forma de almacenamiento interno (float en la terminología de la programación). Presta atención a que la parte decimal se indica con un punto, como en la tradición inglesa, no una coma como en la española. Como vemos, no ha hecho falta poner la parte decimal explícitamente en el segundo caso, como tampoco la parte entera en el cuarto. Python no tiene problemas en asumir que dichas partes implícitas valen 0.

También podemos manejar números grandes:

>>> 1000000000
1000000000
>>> -1000000000
-1000000000
>>> 100_000000_000000_000000
100000000000000000000
>>> -100_000000_000000_000000
-100000000000000000000

Desde la versión 3.6 de Python podemos usar el subrayado como separador numérico para los millares, millones, etc. (realmente podemos colocar un subrayado en cualquier parte del número, pero lo razonable es usarlos para mejorar la legibilidad). Podemos observar que el rango de valores es muy amplio. De hecho, los números enteros no tienen límite en Python, mientras la máquina tenga capacidad de almacenamiento.

1.1.2 Operadores aritméticos

Todo lenguaje de programación puede utilizar los números para efectuar cálculos. Esa es la base de funcionamiento de un ordenador. Los cálculos se realizan utilizando operadores, con los cuales creamos expresiones. Veamos algunos ejemplos:

>>> 20+7
27
>>> 10.5+1.5
12.0
>>> 20-7
13
>>> 10.5-1.5
9.0
>>> 20*7
140
>>> 10*0.5
5.0
>>> 20/7
2.857142857142857
>>> 10.5/1.5
7.0

Hemos utilizado los operadores + (suma), - (resta), * (multiplicación) y / (división). La suma, resta y multiplicación devuelven valores enteros si todos los operandos son enteros, y float si alguno de los operandos es de este tipo. La división siempre devuelve float. Podemos efectuar divisiones enteras con el operador // y calcular el resto (módulo) con el operador %.

>>> 20//7
2
>>> 20%7
6

Completan la lista de operadores el de negación o inversión de signo; - (aplicado a un único valor) y el de exponenciación o potenciación; **. x**n representa la expresión xn.

>>> -2
-2
>>> -(-2)
2
>>> 10**2
100
>>> 2**10
1024

El último valor es un número muy habitual en el medio informático, la décima potencia de dos; 1024 o 1Kb. Vemos en el segundo ejemplo una particularidad, hemos utilizado paréntesis para aplicar un operador a una expresión. Los paréntesis nos ayudan a formular expresiones más complejas resolviendo el orden en que se evalúan los operadores. Cada operador tiene una precedencia (o prioridad); siempre se evalúan antes los de precedencia mayor que los de menor, y en casos de igual precedencia la evaluación se produce de izquierda a derecha. Si agrupamos expresiones mediante paréntesis, el contenido de estos se evalúa antes que la parte exterior.

1.1.3 Precedencia de los operadores

A continuación mostramos la tabla de prececencia de los operadores:


Más prioridad
** Exponente a**b ab
-Negación-a-1 x a
*
/
//
%
Multiplicación
División
División entera
Módulo
a*b
a/b
a//b
a%b
a x b
a / b
int(a / b)
a - (int(a / b) x b)
+
-
Suma
Resta
a+b
a-b
a + b
a - b
Menos prioridad

La precedencia crece de abajo arriba, por grupos. Las operaciones en el mismo grupo tienen la misma precedencia. Todas las operaciones aceptan valores numéricos en general, tanto float como int.

>>> 10.5//2
5.0
>>> 10.5%2
0.5
>>> 10//2.5
4.0
>>> 10%2.5
0.0

Podemos combinar operaciones creando expresiones más complejas:

>>> 10+2*5
20
>>> 5*10+2
52

Para garantizar que una expresión se evalúa de la manera deseada utilizamos los paréntesis.

>>> 10+2*5**2
60
>>> (10+2)*(5**2)
300
>>> 10+(2*5)**2
110

La primera expresión se evalúa como:

10 + (2 x 52)

La segunda equivale a:

(10 + 2) x 52

Y la tercera a:

10 + (2 x 5)2

Utilizando los operadores adecuadamente combinados mediante paréntesis podemos evaluar expresiones de gran complejidad.

1.1.4 Operadores de comparación y valores lógicos o booleanos

Hay un tercer tipo numérico muy especializado, los valores de certeza, lógicos o booleanos (boolean). Consiste en solo dos valores denominados True y False. Por cierto, en ambos casos la inicial debe ser mayúscula, Python distingue entre mayúsculas y minúsculas, para el intérprete las palabras true y false no significan nada y provocarían un error. El valor True representa la confirmación (certeza) de una condición y el valor False su negación (falsedad). Los valores lógicos suelen obtenerse como resultado de una expresión de comparación, que es aquella que utiliza los operadores de comparación.

He aquí la lista de los operadores de comparación en Python:

< Menor que
<= Menor o igual que
== Igual a
>= Mayor o igual que
> Mayor que
!= Distinto de

Los operadores devuelven True si se cumple la condición y False en caso contrario. La precedencia es igual para todos ellos, y menor que la de los operadores aritméticos, por lo que podemos comparar expresiones y saber si se cumplen las relaciones solicitadas.

Veamos un ejemplo:

>>> 100==10
False
>>> 100==100
True
>>> 100.0!=100
False
>>> 100!=10
True
>>> 100>50>10
True
>>> 100>50<10
False
>>> 10*10>=100
True
>>> 10**-1>1
False

Las comparaciones se comportan como es de prever, presta atención a la tercera, estamos comparando un número float y un entero, pero no le crea ningún problema al intérprete. Siempre que utilizemos diferentes tipos de números en la misma expresión los de tipo "inferior" son transformados en el tipo "superior", de ahí que cuando intervenía un número float en una suma, resta o multiplicación con enteros el resultado fuese también float. También podemos concatenar expresiones de comparación, que se evalúan de izquierda a derecha, o comparar operaciones, estas son evaluadas primero y lo que comparamos es su resultado.

Los valores de tipo bool pueden ser utilizados directamente. Podemos teclear lo siguiente:

>>> False
False
>>> True
True

Podemos usarlos como otros números, en expresiones matemáticas o relacionales:

>>> 10-True
9
>>> 10+False
10
>>> False==0
True
>>> 1==True
True
>>> 10==True
False
>>> TrueFalse
True

Aquí hay alguna sopresa. Si utilizamos True en una expresión aritmética se comporta como si valiese 1. De hecho es transformado al tipo numérico superior, entero (int) o float y adopta el valor 1 o 1.0. Por otra parte, el valor numérico de False es 0, como cabía esperar.

1.1.5 La función type(), conversiones entre tipos

Vamos a presentar nuestra primera función. Una función es una orden de python que se caracteriza por poder recibir unos valores (argumentos) con los que efectúa alguna clase de proceso. Una función puede tener valor de retorno o no, en el primer caso el valor de retorno será mostrado por el intérprete, y en el segundo caso el intérprete no mostrará nada. Una función es invocada mediante su nombre y siempre recibe a continuación los argumentos entre paréntesis y separados por comas, incluso una función que no recibe argumentos debe invocarse con los paréntesis a continuación del nombre y nada entre ellos.

función_sin_argumentos()

Nuestra primera función va a ser type(), que en su forma más simple se usa type(objeto) y devuelve el tipo de objeto. Objeto, de momento puede ser cualquiera de los valores que hemos aprendido a utilizar hasta ahora. En realidad podemos pasar cualquier palabra o expresión que tenga sentido para el intérprete. Vamos a verla en acción

>>> type(10)
<class 'int'>
>>> type(10.1)
<class 'float'>
>>> type(False)
<class 'bool'>
>>> type(type)
<class 'type'>

Vemos que, efectivamente, los valores numéricos pueden ser de los tipos int, float y bool, y que podemos llamar a la función pasándole su propio nombre que resulta ser de tipo type, lo cual no es demasiado sorprendente.

Ahora bien, int, float y bool no son solamente los indicadores de los tipos. Anteriormente hemos visto que los valores pueden ser cambiados de tipo cuando en una operación se mezclan tipos diversos, pero de hecho podemos forzar la transformación utilizando las funciones de conversión que (como puedes imaginar) son:

int(valor)Transforma valor en tipo entero
float(valor)Transforma valor en tipo flotante
bool(valor)Transforma valor en True o False

Valor debe ser sustituído por un número o una expresión que devuelva un número. Usemos el intérprete para comprobarlo:

>>> int(3.14)
3
>>> int(True)
1
>>> float(10)
10.0
>>> float(False)
0.0
>>> bool(10)
True
>>> bool(0.00000000001)
True
>>> int("100")
100

La conversión de flotante a entero consiste en truncar la parte decimal y quedarse con lo que hay a la izquierda del punto. La conversión de booleano a entero es 0 para False y 1 para True. La conversión de entero a flotante consiste en añadir el punto decimal y a la derecha un valor 0, la conversión de booleano a flotante produce 0.0 para False y 1.0 para True, por último la conversión de cualquier cosa a booleano considera True todo valor diferente de cero y False exclusivamente a este último valor. En el último caso podemos ver una conversión de una nueva clase de datos, una cadena de caracteres, en un valor numérico. Para este tipo de conversión la cadena debe representar un valor adecuado o se producirá un error.

1.1.6 Valores de texto

Además de los valores numéricos, la otra clase básica de datos son las cadenas de caracteres (str por "character strings"). Una cadena de caracteres es simplemente un texto, una serie de letras y símbolos tipográficos. Para indicar que un dato es una cadena tenemos que utilizar comillas (‘texto’) o comillas dobles (“texto”) tanto al principio como al final. Ambos tipos de comillas son aceptables, pero siempre debe utilizarse en el cierre el mismo tipo que en la apertura. Probémoslo directamente:

>>> "Hola"
'Hola'
>>> 'Adiós'
'Adiós'

Si olvidamos el uso de las comillas obtendremos algo como:

>>> Hola
Traceback (most recent call last):
 File "<pyshell# 2>", line 1, in <module>
  Hola
NameError: name 'Hola' is not defined

El color rojo ya nos indica que hay algún problema. Esta es la apariencia de los mensajes de error en IDLE, el error está detallado en la última línea: NameError: name 'Hola' is not defined. Python ha buscado algo llamado Hola y al no encontrarlo ha generado un error de tipo NameError. El intérprete busca un sentido a todo lo que procesa, es capaz de entender los números y las cadenas de texto entrecomilladas, pero también puede entender cualquier otra palabra, siempre que esa palabra esté en su diccionario interno y la palabra Hola no lo está. Más adelante iremos aprendiendo qué palabras están incluídas en ese diccionario.

Hagamos algún experimento con nuestra nueva clase de datos

>>> type("Hola")
<class 'str'>
>>> "Hola"+'Adiós'
'HolaAdiós'
>>> "Hola"*4
'HolaHolaHolaHola'

No es ninguna sorpresa que el tipo que nos devuelve la función type() es str. Puede que te sorprenda más comprobar que el tipo str admite las operaciones de suma y multiplicación. En este caso la suma equivale a un proceso que llamamos concatenación, las cadenas de caracteres se unen entre sí formando otra más larga. Hay que notar que la concatenación se produce tal cual estén definidas las cadenas, no se inserta ningún espacio o separador, de ser necesario tenemos que colocarlo nosotros mismos. La multiplicación devuelve la cadena repetida el número de veces por el que multipliquemos, que debe ser un valor entero. Esto puede resultar útil para crear líneas de separación entre bloques de texto. Podemos usar:

>>> "*")*20
'********************'
>>> "-")*20
'--------------------'
>>> "_")*20
'____________________'

O emplear los caracteres para crear recuadros del juego de caracteres Unicode. Más adelante profundizaremos más en ese tema. Vamos a aprovechar las cadenas de caracteres para aprender nuevas funciones. Lo haremos de la mejor manera que es practicando con ellas.

>>> str()
''
>>> str(100)
'100'
>>> len("En un lugar de la Mancha...")
27

Como vamos viendo hasta ahora, el nombre de la clase str es también una función de conversión si lo invocamos con un argumento entre paréntesis. Si el argumento no existe creamos una cadena vacía, si es otro tipo de dato es convertido a una representación en forma de texto, o secuencia de caracteres. La función len() (de length, longitud) proporciona el número de items en un dato de tipo secuencia, esto es, un dato que está constituído por una serie de valores en vez de un valor único como los tipos numéricos. Obviamente, una cadena de caracteres es un dato de tipo secuencia, los items que la componen son cada uno de los caracteres individuales, así que len() aplicado a una cadena nos devuelve el número de caracteres que la componen.

Otra de las funciones más útiles es la función print() que sirve para presentar datos. Realmente en el modo interactivo no le sacaremos mucho partido, pero en el próximo capítulo será una herramienta fundamental. La función print() se invoca mediante su nombre y una serie de argumentos separados por comas entre los paréntesis.

¡¡¡RECUERDA: si es una función, siempre debe ir seguida de paréntesis, con o sin argumentos entre ellos!!!

>>> print(10,"Hola",2*5,10>100)
10 Hola 10 False

Print presenta en el terminal de texto (otro concepto que dejamos para más adelante) de una forma comprensible para el usuario humano los datos que le adjuntemos, separados por espacios, y con un salto de línea al finalizar (esto quiere decir que la próxima salida de texto se producirá en la línea posterior). Print es una función de gran potencia y todos estos comportamientos por defecto pueden configurarse para obtener la representación que más nos convenga.

1.1.7 Variables. Sentencias de asignación

Empezarás a darte cuenta de que si cada vez que quieres utilizar un valor tienes que teclearlo, además de un aburrimiento resulta terriblemente poco práctico. Se supone que programamos para que el ordenador haga el trabajo duro por nosotros, y hasta ahora no es así. Uno los mecanismos que nos llevan a ese objetivo y que ahora vamos a ver es el uso de variables.

Una variable es un identificador que recibe un valor y que puede utilizarse a partir de entonces para representar dicho valor y operar con él. Un identificador es una serie de letras, una palabra, abreviatura o combinación de palabras que cobra sentido para el intérprete a partir del momento en que lo utilizamos del modo adecuado. Podemos elegir libremente dicho nombre, pero teniendo en cuenta que:

Llegados a este punto, vamos a ver la famosa lista de palabras reservadas, que presentamos a continuación:

Palabras reservadas de Python 3.8.3
and as assert assync await break class
continuedefdelelifelseexceptFalse
finallyforfromglobalifimportin
islambdaNonenonlocalnotorpass
raise return True try while with yield

Son unas cuantas, a lo largo del curso iremos entendiendo su función, de momento hay dos viejas conocidas en esa lista, los valores True y False.

Podemos añadir algunas observaciones sobre los nombres de variables. La primera es una recomendación y una buena práctica que todo programador aplica. Se trata de usar nombres SIGNIFICATIVOS, esto quiere decir que el nombre nos sirva para entender el contenido de la variable. Además de mejorar la legibilidad del código nos permitirá evitar errores y lo más importante, comprender el programa si lo revisamos un tiempo después, o si ha sido programado por otra persona.

>>> autor="Cervantes"
>>> título="El ingenioso hidalgo don Quijote de la Mancha"
>>> títuloBreve="Don Quijote"
>>> editor="Juán de la Cuesta"
>>> año_primera_edición=1605
>>> SegundaEdición=1605
>>> lugarDePublicación="Madrid"

Es fácil colegir que si luego vemos variables como Autor o Título será más sencillo entender lo que está ocurriendo a lo largo del programa. Si es necesario podemos combinar varias palabras, pero no olvidemos que los espacios no están permitidos, por lo que podemos emplear diversas opciones, de las que tenemos tres ejemplos en el listado anterior. Una de ellas es reemplazar los espacios por guiónes bajos como en primera_edición, y otra, que es la que se suele emplear dentro del propio PYTHON es la llamada CamelCase, que consiste en juntar las palabras con la primera letra de cada una en mayúscula (La denominación viene por el aspecto de jorobas que produce la alternancia de mayúsculas y minúsculas). Dentro de este último estilo podemos distinguir UpperCamelCase cuando la primera letra es también mayúscula, y lowerCamelCase cuando la primera letra es minúscula, este último es el estilo utilizado en los identificadores del lenguaje Python y sus librerías.

Repasemos más atentamente el último listado. Hemos utilizado un nuevo operador, el de asignación. Este es el que en Python nos permite crear una variable, en el momento en que realizamos la asignación el nombre de la variable cobra valor para el intérprete. El operador es "=" y debemos evitar confundirlo con el de comparación de igualdad "==". Esta es una equivocación muy habitual en los principiantes, y puede dar muchos quebraderos de cabeza. La estructura de una sentencia de asignación es la siguiente:

IdentificadorOperador
de
asignación
Valor
númeroPI = 3.141592653589

Se puede pensar que la asignación se realiza de derecha a izquierda, el valor de la derecha es "volcado" en el contenedor de la izquierda, al que nos referimos mediante el nombre empleado. A partir de esta sentencia el nombre de variable númeroPI almacena el valor de π y puede ser empleado en cualquier expresión o como argumento de una función, o de la forma en que podríamos emplear el valor 3.1415...  Si hasta ahora no te has fijado, te llamo la atención sobre un detalle de los nombres empleados. Anteriormente dijimos que debías incluír caracteres alfanuméricos o "_", pero en la versión actual de Python la definición de caracter alfanumérico se ha ampliado para incluír muchos símbolos de otros lenguajes, por ejemplo las vocales acentuadas y la "ñ" que hemos utilizado en los ejemplos. En cualquier caso, recuerda que Python distingue entre mayúsculas y minúsculas. En general es mejor no utilizar mayúsculas para simplificar el mecanografiado de los programas (salvo el estilo CamelCase ya mencionado), pero eso es elección del programador. Otra cosa que habrás notado es que la sentencia de asignación no devuelve ningún valor, por eso el intérprete no muestra ninguna salida.

Hagamos más experimentos con la asignación de variables:

>>> x,y=100,200
>>> x
100
>>> y
200
>>> a=b=c=10*3
>>> a
30
>>> b
30
>>> c
30
>>> x,y=y,x+y
>>> x
200
>>> y
300

Podemos hacer asignaciones múltiples si separamos por comas tanto los nombres de variable (a la izquierda del operador =) como los valores asignados (a la derecha del operador =). Si no coinciden el número de nombres y el de valores se producirá un error. También podemos encadenar asignaciones para proporcionar el mismo valor a un conjunto de variables, como el el segundo ejemplo, y los valores asignados pueden ser expresiones. Estas son evaluadas primero y los valores resultantes adjudicados a las variables. Por último, en el tercer caso hemos modificado las variables x e y por expresiones con ellas mismas. Podemos comprobar como funciona la asignación, en primer lugar se evalúan TODAS las expresiones a la derecha del operador "=" de izquierda a derecha, en el orden de escritura normal, luego se produce la asignación a las variables indicadas a la izquierda del signo "=". Si se fueran produciendo las asignaciones según se evaluaran las expresiones, x adoptaría el valor de y (200) y luego y adoptaría el de la expresión x+y, o sea, 200+200 y terminaría valiendo 400. En este último ejemplo hemos comprobado la principal característica de las variables y es la de poder cambiar su valor a lo largo del programa, de otro modo solamente serían etiquetas, nombres que reemplazan a una expresión más compleja o más larga.

Un último ejemplo acerca de la asignación de variables:

>>> var=10
>>> var
10
>>> type(var)
<class 'int'>
>>> var+=10
>>> var
20
>>> var *=10
>>> var
200
>>> var-=100
>>> var
100
>>> var/=10
>>> var
10.0
>>> type(var)
<class 'float'>
>>> var="Adiós"
>>> type(var)
<class 'str'>

Vemos que las variables tienen un tipo que corresponde al valor que tengan asignado en cada momento, al cambiar dicho valor el tipo cambia en consecuencia. Y también acabamos de presentar en sociedad los operadores de asignación condensados, que mostramos a continuación en una tabla:

OperadorUsoResultado
+= variable+=valor variable=variable + valor
-=variable-=valorvariable=variable - valor
*=variable*=valorvariable=variable * valor
/=variable/=valorvariable=variable / valor
//=variable//=valorvariable=variable // valor
%=variable%=valorvariable=variable % valor
**= variable**=valor variable=variable ** valor

Estas formas de asignación resultan más compactas y más legibles. En concreto el operador "+=" se usa típicamente para implementar contadores con una sentencia como esta:

contador+=1

Para tratar de explicarte la importancia de esta sencilla sentencia, otro lenguaje de programación, el lenguaje C, implementa esta última operación de incrementar un valor de uno en uno mediante la sintaxis: contador++, y es tan utilizado que el sucesor del lenguaje C se llama C++.

1.1.8 Más datos de tipo secuencia: Tuplas y listas

Conocemos ya un dato especializado de tipo secuencia, la cadenas de caracteres, y vamos a introducir dos nuevos tipos mucho más generales, las tuplas y las listas. Prueba en el intérprete las siguientes líneas:

>>> 10,20
(10, 20)
>>> _
(10, 20)
>>> type(_)
<class 'tuple'>

Acabamos de ver dos cosas interesantes, la primera es un nuevo tipo de datos que recibe la denominación tuple, que consta de valores entre paréntesis separados por comas. La segunda es el identificador "_", que en el modo interactivo almacena el resultado de la última expresión, y podemos emplearlo para concatenar diversas operaciones unas a partir del resultado de otras. Prosigamos indagando las propiedades de las tuplas:

>>> tupla=10,20,30
>>> tupla
(10, 20, 30)
>>> tupla==(10,20,30)
True
>>> tupla==10,20,30
(False,20,30)

Podemos asignar una tupla sin necesidad de usar los paréntesis siempre y cuando a la izquierda del operador de asignación (el signo =) solamente haya una variable, y a la derecha un grupo de valores separados por comas. Podemos comparar tuplas, pero ojo, mira el resultado de la última línea, el intérprete ha visto tres valores:

Con esos tres valores se ha formado la tupla resultante. Si ahora tecleamos:

>>> tupla=tupla+_
>>> tupla (10, 20, 30, False, 20, 30)

Las tuplas admiten también operaciones como la suma (concatenación) y el producto (repetición), observa que hemos utilizado la variable _ del intérprete para utilizar el último valor. Probemos las nuevas posibilidades:

>>> tupla=(10,20,30)
>>> tupla
(10, 20, 30)
>>> tupla+10
Traceback (most recent call last):
File "<pyshell# 60>", line 1, in <module>
tupla+10
TypeError: can only concatenate tuple (not "int") to tuple

>>> tupla+(40,50,60)
(10, 20, 30, 40, 50, 60)
>>> tupla*2
(10, 20, 30, 10, 20, 30)
>>> tupla
(10, 20, 30)

Al intentar concatenar una tupla con otro tipo de dato se produce un error, debemos concatenar tuplas entre sí. Por otra parte, en la antepenúltima y la penúltima operaciones hemos obtenido el resultado de la suma de dos tuplas y el producto de una tupla por un número entero, pero si te fijas bien verás que no hemos asignado esos resultados y por consiguiente tupla sigue valiendo lo mismo. Un ultimo vistazo a la sintaxis de las tuplas:

>>> tupla+=(40)
Traceback (most recent call last):
File "<pyshell# 79>", line 1, in <module>
tupla+=(40)
TypeError: can only concatenate tuple (not "int") to tuple

>>> tupla+=(40,)
>>> tupla
(10, 20, 30, 40)
>>> tupla+=tuple(50)
Traceback (most recent call last):
File "<pyshell# 87>", line 1, in <module>
tupla+=tuple(50)
TypeError: 'int' object is not iterable

tupla+=tuple("50")
>>> tupla
(10, 20, 30, 40, '5', '0')
tuple()
()

Concentrando unos cuantos puntos podemos ver que se pueden utilizar los operadores de asignación condensados += y *=, la primera línea genera un error, porque el valor 40 entre paréntesis es una expresión numérica, cuyo resultado es el entero 40. En cambio la sintaxis (40,) funciona perfectamente. De la misma manera vemos que la función tuple() que por supuesto genera una tupla a partir de un conjunto de valores, produce un error si le pasas un único valor, TypeError: 'int' object is not iterable, el parámetro tiene que ser iterable, ya veremos en que consiste esto, pero de momento basta con saber que una lista de valores es iterable, y una cadena de caracteres también lo es, el penúltimo experimento con la cadena "50" funciona, aunque tal vez su resultado no sea el que esperabas. Al iterar la cadena lo que ha hecho es descomponerla en los caracteres individuales que la componen, el '5' y el '0' y los ha anadido a tupla. Como puedes ver los valores de una tupla no tienen que ser del mismo tipo, incluso puedes incluir más tuplas como un elemento más, con lo cual se pueden crear tablas multidimensionales. La función tuple() sin argumentos nos permite crear una tupla vacía.

Las tuplas tienen su función, por ejemplo son el tipo de datos ideal para almacenar conjuntos como los nombres de los días de la semana o los meses del año para luego usarlos en una presentación de fechas, pero tienen una característica que las hace inadecuadas para otros usos, y es que son inmutables. Una vez creada una tupla sus elementos siguen siendo siempre los que sean. Aunque hayamos visto operaciones con tuplas, en realidad no modificábamos las tuplas en si, simplemente creábamos nuevas tuplas combinando datos y al asignarlas a una variable, nos pensamos que la tupla original ha cambiado, pero solo ha cambiado el contenido de la variable que es ahora una tupla distinta, no la misma tupla cambiada. Por cierto, las cadenas de caracteres también son inmutables.

Aquí entra en acción el siguiente tipo de datos, que en realidad se parecen mucho a las tuplas pero son mutables, el tipo de datos lista (list). Declaramos una lista indicando un conjunto de valores, separados por comas, entre corchetes:

>>> milista=[10,20,30]
>>> milista
[10, 20, 30]
>>> type(milista)
<class 'list'>

Hasta aquí todo muy similar, salvo la sintaxis de los corchetes. Con lo que ya sabemos podemos entender que una lista acepta las operaciones de concatenación mediante el operador + y de repetición mediante el operador *.

>>> milista+=[40]
>>> milista
[10, 20, 30, 40]
>>> milista*=2
>>> milista
[10, 20, 30, 40, 10, 20, 30, 40]

A diferencia de las tuplas, un solo elemento entre corchetes se considera una lista válida, dado que no hay ambigüedad ninguna como en el caso de los paréntesis. Podemos también utilizar la función list() para crear listas.

>>> list()
[]
>>> list(10)
Traceback (most recent call last):
File "<pyshell# 106>", line 1, in <module>
list(10)
TypeError: 'int' object is not iterable

>>> list(10,20)
Traceback (most recent call last):
File "<pyshell# 107>", line 1, in <module>
list(10,20)
TypeError: list expected at most 1 argument, got 2

>>> list((10,20))
[10, 20]
>>> list("HOLA")
['H', 'O', 'L', 'A']

Podemos crear una lista vacía, pero en caso de utilizar un argumento tiene que ser iterable, no vale un valor simple. Tampoco funciona la sintaxis de poner varios valores separados por comas, nos dice que como mucho se espera un argumento y que hemos escrito dos. Funciona, en cambio si ponemos una tupla o una cadena, en el último caso separando los caracteres como vimos en el caso de la función tuple().

Las listas son un mecanismo muy potente para manejar conjuntos de datos, para lo cual es importante el acceso libre a cualquier parte del conjunto, comenzando por los elementos individuales. Esto se realiza mediante la siguiente sintaxis:

>>> lista=[10,20,30,40,50,60,70,80,90,100]
>>> len(lista)
10
>>> lista[0]
10
>>> lista[9]
100

Vemos que podemos usar la función len() que en su momento aprendimos con las cadenas de texto. Los elementos de cualquier secuencia están indexados comenzando por la posición 0 y terminando por len(secuencia)-1. Podemos acceder a cualquier elemento mediante el nombre de la secuencia y el índice entre corchetes.

>>> lista[10]
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
lista[10]
IndexError: list index out of range

Si intentamos ir más allá de las posiciones existentes nos devolverá un error. En cambio podemos usar índices negativos para contar desde el final de la secuencia:

>>> lista[-1]
100
>>> lista[-3]
80

Extendiendo la misma notación podemos referirnos a secciones de la secuencia (lista, tupla o cadena).

>>> lista[2:5]
[30, 40, 50]
>>> lista[5:]
[60, 70, 80, 90, 100]
>>> lista[:5]
[10, 20, 30, 40, 50]
>>> lista[5:2]
[]
>>> lista[-20:20]
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
>>> lista[-5:-1]
[60, 70, 80, 90]
>>> lista[0:-1]
[10, 20, 30, 40, 50, 60, 70, 80, 90]

Obtenemos una porción (slice en inglés) de la secuencia. Debemos indicar la posición de inicio mediante el índice del primer elemento de la porción, pero el segundo índice indica la posición del elemento posterior a la porción, no obtenemos ese elemento sino el inmediatamente anterior. En el primer ejemplo tenemos una sub-lista con los elementos de índices 2, 3 y 4 de la lista original, no obtenemos la posición 5. Con los ejemplos segundo y tercero vemos que si no especificamos la última posición se asume que obtenemos todos los elementos desde la posición inicial al final de la secuencia y si no indicamos la primera posición se asume que la porción comienza al principio de la secuencia (la posición lista[0]). Si el segundo índice es menor que el primero obtenemos una lista vacía y, si los índices indican posiciones fuera de rango, no se produce un error sino que devuelve los elementos disponibles. También podemos usar índices negativos para obtener elementos desde el final de la cadena, pero observa que lista[0:-1] no devuelve la lista completa; como ya hemos dicho el último índice no se devuelve sino el inmediatamente anterior.

Con esto damos por terminada esta introducción al lenguaje Python mediante el intérprete interactivo, a partir de ahora vamos a explorar las posibilidades de creación de secuencias de instrucciones mediante ficheros .PY, lo que constituye de hecho la creación de programas en Python. Antes vamos a recapitular los conceptos aprendidos hasta ahora.

1.1.9 RESUMEN

Tipos de datos
Numéricos: Enteros
Flotantes
Booleanos
100
100.0
True, False
int()
float()
bool()
Secuencias: Cadenas de texto
Tuplas
Listas
"La princesa está triste"
(10,20,30)
[10,20,30]
str()
tuple()
list()
Operadores
Aritméticos: +
-
*
/
//
%
**
-
suma
resta
multiplicación
división
división entera
módulo
potencia
cambio de signo
x + y
x - y
x * y
x / y
x // y
x % y
x ** y
- x
Operaciones con secuencias: +
*
concatenación
repetición
Paréntesis: ( ) Permiten organizar el orden de evaluación
Comparaciones: <
<=
==
>=
>
!=
menor que
menor o igual a
igual a
mayor o igual a
mayor que
distinto de
Asignación: =
Asigna un valor a un identificador (variable)
Asignación aumentada: +=
-=
*=
/=
//=
%=
**=
Modifican la variable combinándola con otro valor
Funciones
type( ) Proporciona información sobre el tipo de un valor o variable
len() Devuelve un valor entero con el número de elementos de una secuencia
print() Muestra una representación en forma de texto de los valores indicados
Variables
Identificadores: Deben comenzar por un caracter alfabético o "_"
Deben constar de caracteres alfanuméricos o "_"
Pueden ser de cualquier longitud
No deben coincidir con palabras reservadas (Keywords)
nombre_de_variable
nombreDeVariable
NombreDeVariable
Nomenclatura habitual para identificadores de varias palabras
lowerCamelCase (La forma de Python)
UpperCamelCase
Variable _ En modo interactivo guarda el resultado de la última expresión
Acceso a elementos en secuencias
Índices: secuencia[índice] Devuelve el elemento en la posición índice
Porciones: secuencia[start:end] Devuelve los elementos comprendidos entre
la posición start y el anterior a end
1.2 El modo de edición de programas

Terminamos aquí la toma de contacto con el intérprete interactivo. Igual que comentábamos en el epígrafe de la creación de variables que no es práctico teclear los valores cada vez que necesitamos usarlos, tampoco lo es teclear el código cada vez, aunque es un buen medio de aprendizaje. Un programador se dedica a crear programas, esto es, ficheros con secuencias de instrucciones que realizan un proceso. Los programas se guardan para ejecutarlos cuantas veces sean necesarias o para editarlos y modificar su comportamiento. Los programas Python se guardan en archivos de texto con extensión .py

Podemos editar un programa con cualquier editor de texto plano, pero es más conveniente usar un Entorno integrado de desarrollo (IDE), que nos proporciona ayudas como resaltar la sintaxis mediante colores, ejecutar directamente el programa desde el mismo editor y muchas otras. El entorno de desarrollo que Python incluye por defecto es el programa IDLE, que ya venimos usando en modo interactivo. Ahora vamos a crear programas, para ello usamos la opción File->New File o la combinación de teclas "Ctrl+N". Nos aparece una nueva ventana cuya diferencia es la ausencia del prompt y la numeración de líneas a la izquierda. Si no aparece esta última, abre el menú Options->Configure IDLE y en la pestaña "General" dentro del recuadro "Editor Preferences" marca la opción "Show line numbers in new windows".

Vamos a crear nuestro primer programa. Una tradición en el mundo de la programación es comenzar con un sencillo código llamado "Hola, mundo" ("Hello, world") que se limita a imprimir esta frase. Aunque nuestros conocimientos del lenguaje están por encima de este ejemplo vamos a mantener la tradición.

'''
 Hola, mundo
 Mi primer programa en PYTHON
'''

print("Hola, mundo") #Escribe el texto "Hola, mundo"

Una vez tecleado este código lo ejecutamos con la opción Run->Run Module o la tecla "F5", nos dirá que antes de ejecutarlo debemos guardarlo, aceptamos y le damos un nombre, que en este caso bien puede ser "Hola, mundo". Obtendremos la siguiente salida:

============= RESTART: C:/Users/User/Documents/Python/Hola, mundo.py =============
Hola, mundo
>>>

Analizando el programa encontramos un par de novedades. Las líneas 1 a 4 son una cadena de texto. Cuando usamos comillas triples al comienzo de una línea creamos una cadena de texto que puede extenderse entre líneas, esto también se usa para comentar el código, y para generar documentación automáticamente sobre los programas. No puede haber ningún caracter salvo espacios antes de las comillas triples iniciales, ni después de las finales.

La línea que hace el "trabajo duro" es la 6, que usa la función print() para imprimir el texto "Hola, mundo". A continuación hay algo especial, el texto ha sido marcado por el editor con un color diferente. Esto se debe a que cualquier contenido detrás del caracter # no entrecomillado, esto es, que no forma parte de una cadena de texto, y hasta el final de la línea se considera un comentario. Los comentarios son ignorados por el intérprete, solo sirven para aclarar el funcionamiento del código para un posible lector humano. Es una buena práctica de programación utilizar comentarios con suficiente frecuencia.

En cuanto a la salida, nos fijamos en que el intérprete indica que estamos ejecutando el fichero:  Hola, mundo.py,   mostrando la ruta completa de este. A continuación la salida del programa en sí se limita a imprimir la frase "Hola, mundo", que era el resultado buscado.

Como hemos observado, un programa es una secuencia de instrucciones que se van ejecutando una a continuación de la anterior. Los programas Python se guardan en ficheros de texto plano con la extensión .py como hemos visto. Podemos abrirlo con el bloc de notas y obtenemos el siguiente resultado:

Podríamos editar así nuestros programas, pero merece la pena el resaltado por colores, la indentación automática y las demás ventajas que nos proporciona IDLE.

1.2.1 El flujo del programa. Sentencias condicionales

Los programas se ejecutan habitualmente en el orden normal de lectura, línea por línea, pero sería muy limitado si solo pudieran hacerlo así, un programa concebido de esta manera siempre realizaría la misma secuencia de órdenes y no tendría ninguna versatilidad. Queremos que el programa pueda reaccionar a lo que va ocurriendo, según los resultados de los cálculos, la entrada del usuario y muchas otras variables. Para esto disponemos de un conjunto de herramientas que denominamos sentencias de control de flujo. Observa el siguiente código:

x=input("¿Cuantos años tienes?")

print("Hola",end=" ")
if int(x)<10:
print("¿Tu papá te deja jugar con esto?")

Te presentamos informalmente la función input(), se trata en cierto modo de la función opuesta a print(), si esta vuelca un contenido por la salida estándar, aquella recibe una entrada del usuario por la entrada estándar (que es el teclado). El argumento opcional es una cadena de texto con un mensaje que indica al usuario lo que se espera de él (prompt). La función input() siempre devuelve una cadena de texto, como queremos obtener un valor numérico usamos la función int() para realizar la conversión. Si el usuario introduce un valor que no se corresponde con un número entero se producirá un error. Pulsando "F5" ejecutaremos el programa, pero antes IDLE nos pide que lo guardemos, podemos llamarlo If.py El resultado sería algo así:

============= RESTART: C:/Users/User/Documents/Python/If.py =============
¿Cuantos años tienes?29
Hola
>>>

La sentencia if es una sentencia condicional; el bloque asociado con ella solo se ejecuta cuando la expresión posterior devuelve el resultado True. Aquí vemos una forma real de utilizar los operadores de comparación. La sentencia if consiste en la palabra clave if, seguida de una expresión que es evaluada y del caracter dos puntos ":". La línea o líneas siguentes especifican un bloque de sentencias, y deben indentarse con respecto a la sentencia condicional. Mientras dure la indentación consideramos que las instrucciones forman parte del bloque y solo se ejecutarán si la expresión del if tiene el resultado True. Ejecutemos el programa otra vez pero esta vez le indicaremos una edad menor de diez.

============= RESTART: C:/Users/User/Documents/Python/If.py =============
¿Cuantos años tienes?9
Hola ¿Tu papá te deja jugar con esto?
>>>

En este caso la expresión int(x)<10 devuelve el valor True y se ejecuta la línea 5. Vamos a mirar con detalle todo el programa para resaltar un par de aspectos. La línea 1 es una sentencia de asignación. Como ya dijimos en la sección correspondiente, la expresión a la derecha del operador de asignación es evaluada en primer lugar, y luego se crea un identificador al que le asignamos el resultado de dicha expresión. La expresión en este caso es la función input() con un argumento de texto. La función input escribe en la salida estándar (consola de texto) el argumento y espera una entrada del usuario por la entrada estándar (teclado). El argumento sirve para indicar al usuario lo que esperamos que haga, en caso contrario la pantalla quedaría congelada con un cursor parpadeante y no tendríamos ni idea de lo que el programa está haciendo. Vemos que el prompt se junta con la entrada, conviene siempre terminar el argumento de input con un espacio para crear una separación. Podemos editar lo que tecleamos como respuesta hasta que lo enviemos a la entrada estándar cuando pulsemos <INTRO>, además vemos que lo que tecleamos aparece siempre en la pantalla. Como ya hemos apuntado, el resultado siempre es una cadena de texto (str).

A continuación hemos dejado una línea vacía. Para Python los espacios y líneas en blanco no cuentan en absoluto, se limita a ignorarlos. Es una buena práctica separar bloques lógicos por líneas en blanco para facilitar la legibilidad del código. En este caso separamos la entrada de datos de la salida.

La línea tres es nuestra conocida función print(), que imprime un saludo poco original, pero vemos que hemos añadido otro argumento, en este caso un argumento con nombre. El nombre es end y el valor una cadena con un espacio. El argumento "end" en la función print sirve para cambiar el comportamiento por defecto que consiste en imprimir un salto de línea como terminación. Si ponemos un argumento con nombre end será el valor de dicho argumento lo que se utilizará para terminar la salida.

Las líneas 4 y 5 constituyen el bloque condicional. La primera línea es la sentencia if seguida por la expresión a evaluar y terminando la línea por el caracter dos puntos ":". A continuación van las sentencias que serán ejecutadas solamente si la expresión que sigue a if produce un valor True. Podemos colocar esta sentencia de dos maneras, en la misma línea, a continuación del caracter ":".

if int(x)<10: print("¿Tu papá te deja jugar con esto?")

O en la línea siguiente, indentada respecto a la línea de la sentencia if:

if int(x)<10:
print("¿Tu papá te deja jugar con esto?")

Podemos ejecutar múltiples sentencias dentro del bloque condicional en líneas sucesivas manteniendo la indentación:

if int(x)<10:
print(int(x),"es demasiado poco.")
print("¿Seguro que tus padres te dejan usar esto?")

En realidad podemos poner varias sentencias en la misma línea separadas por el caracter punto y coma ";".

if int(x)<10: print("¿Solo",int(x),"años?"); print("¿No eres demasiado joven para esto?")

En cualquier caso, es más legible y más fácil para editar modificaciones el sistema de múltiples líneas, así que a partir de aquí será el que usemos en este tutorial.

En Python la indentación del código no es un adorno, y no puede utilizarse salvo en los momentos adecuados para señalar bloques de código. En concreto, no se puede indentar código salvo que haya alguna de las sentencias que definen bloques, como la sentencia if. Todo el bloque debe mantener la misma indentación y pueden anidarse unos bloques en otros, pero cuando un bloque se termina debemos volver a la misma posición de antes de empezarlo. Además, aunque esto son recomendaciones de estilo, debemos indentar con espacios mejor que con tabuladores, y cuatro espacios es la medida habitual, que proporciona un buen compromiso entre la visibilidad de los bloques y el ahorro de espacio dentro de la línea. NUNCA debes mezclar espacios y tabuladores.

'''
Ejemplos de indentaciones incorrectas
'''

 print("Esto está mal") # Línea indentada sin que se requiera

if True: # Falta de indentación cuando es obligatoria
print("Esto también")

if 1==1: # Indentación irregular
print("Esto empieza bien")
print("Pero continúa mal")

El editor de IDLE nos facilita la vida también en esto. Cuando introducimos una sentencia que requiere indentación al pulsar INTRO se crea la indentación correcta de cuatro espacios y se mantiene en las líneas posteriores. Una vez que terminemos el bloque, pulsando la tecla de borrado (retroceso) se vuelve a la indentación previa automáticamente. Si pulsamos TAB también se convierte en cuatro espacios automáticamente.

El bloque condicional puede ir seguido de un bloque else, que representa la alternativa si la condición no resulta ser cierta.

#Sentencia condicional con bloque alternativo
x=input("¿Cuántos años tienes?: ")

if int(x)>=18:
print("!Eres mayor de edad!")
else:
if int(x)==17:
print("Te falta 1 año para la mayoría de edad.")
else:
print(f"Te faltan {18-int(x)} años para la mayoría de edad.")

Como de costumbre aprendemos varias cosas nuevas con este ejemplo. Para empezar hemos dejado un espacio en el prompt de la función input para que lo que tecleemos no se mezcle con dicho prompt. Vemos en acción el bloque alternativo else en las líneas 6 a 10, pero también vemos condiciones anidadas; Dentro del bloque else hay un nuevo conjunto condicional if-else, debidamente indentado. Si la edad es inferior a 18 años comprobamos si es inferior solo en un año o en más, para redactar correctamente la respuesta. Así evitamos una salida del tipo.

Te faltan 1 años para la mayoría de edad.

Si ejecutamos el programa tendremos un resultado parecido al siguiente:

============= RESTART: C:/Users/User/Documents/Python/If-else.py =============
¿Cuántos años tienes?: 10
Te faltan 8 años para la mayoría de edad.

La línea 10 incluye otro descubrimiento, una cadena con formato. Una cadena que tiene un caracter "f" inmediatamente antes de las comillas iniciales, en este tipo de cadena lo que encerremos entre corchetes { } se trata como una expresión, es evaluado e intercalado en la posición correspondiente de la cadena de caracteres. En este caso, la expresión 18-int(x) produce el resultado 8, puesto que x es la cadena "10" introducida en la línea 2 mediante la función input().

Para tratar múltiples condiciones en un bloque condicional podemos sustituir el conjunto else: seguido de un nuevo bloque if: por la sentencia elif seguida de la nueva condición a evaluar. Esta se indenta a la misma altura que el if inicial y el else final del bloque, y podemos utilizar cuantos bloques elif queramos. Así podríamos redactar nuestro programa If-else.py de la siguente forma:

#Sentencia condicional con bloque alternativo
x=input("¿Cuántos años tienes?: ")

if int(x)>=18:
print("!Eres mayor de edad!")
elif int(x)==17:
print("Te falta 1 año para la mayoría de edad.")
else:
print(f"Te faltan {18-int(x)} años para la mayoría de edad.")

Comprobamos que esta escritura resulta mucho más compacta y clara.

1.2.2 Operadores lógicos

Frecuentemente no nos basta con evaluar una condición simple, sino que debemos comprobar si se cumple una combinación de condiciones. Podríamos anidar unas sentencias if dentro de otras, pero esto resulta farragoso y poco práctico. Aquí entran en juego los operadores lógicos.


Más prioridad
Operadores lógicos de PYTHON
not Negación lógica not expr si expr==True devuelve False
si expr==False devuelve True
and Y lógico
o producto lógico
expr1 and expr2 Si expr1 y expr2 son ambas True devuelve True
Si una de las dos o ambas son False devuelve False
or O lógico
o suma lógica
expr1 or expr2 Si expr1 y expr2 son ambas False devuelve False
Si una de las dos o ambas son True devuelve True
Menos prioridad

Los operadores lógicos combinan valores booleanos, y nos permiten combinar varias condiciones en una sentencia if.

edad=int(input("Introduce tu edad: "))

#Versión sin operadores lógicos
if edad>=18:
if edad<68
print("Estás en edad de trabajar")

#Versión con operadores lógicos
if edad>=18 and edad<68:
print("Estás en edad de trabajar")

El operador and devuelve True solamente si todas las expresiones son True, si se encuentra una expresión que devuelve False las expresiones posteriores no son evaluadas. El operador or devuelve True si alguna de las expresiones devuelve True, en el momento en que esto ocurra las expresiones posteriores no son evaluadas. Esto nos permite evitar que se evalúen expresiones que provocarían errores.

dividendo, divisor = 2, 0

if divisor!=0 and dividendo%divisor==0:
print(f"{dividendo} es divisible por {divisor}")

Como la primera condición devuelve False no se evalúa la segunda expresión que intentaría efectuar una división por cero produciendo el error:

ZeroDivisionError: integer division or modulo by zero

Más adelante ahondaremos en estos operadores, cuando avancemos en nuestros conocimientos acerca de los valores de tipo secuencia.

1.2.3 Bucles

Hemos visto cómo podemos desviar el flujo de ejecución para seleccionar distintos bloques de instrucciones en función de una condición dada, ahora vamos a completar el control de ejecución con una de las estructuras de programación más características, los bucles. Un bucle, sencillamente, es un bloque de instrucciones que se repiten en virtud de alguna condición. Todos los programas de cierta entidad funcionan básicamente en forma de bucles, por ejemplo mientras esperan la entrada del usuario. De momento vamos a echar un vistazo a las dos sentencias en Python que nos permiten crear bucles: while y for.

Los bucles pueden crear estructuras circulares de programa sin salida, que se repetirían indefinidamente. Eso es lo que se llama un bucle infinito. El intérprete de Python nos permite detener cualquier programa en cualquier momento mediante la combinación de teclas: <CTRL>+<C>
¡Tenlo presente!

Un bucle while comienza por la palabra reservada while, seguida de una condición y finalizando por el caracter dos puntos ":". Mientras la condición se cumpla (o sea, devuelva True) el bloque de sentencias (indentadas) que haya a continuación se ejecutará y volveremos al comienzo del bucle evaluando de nuevo la condición.

#Programa que solicita al usuario responder con "Si"

respuesta="" #Inicializamos la variable para la primera evaluación

while respuesta!="Si":
respuesta=input("Para continuar responde \"Si\" ")

Lo ejecutamos pulsado F5 y podemos obtener algo de este tipo:

============= RESTART: C:/Users/User/Documents/Python/while.py =============
Para continuar responde "Si"
Para continuar responde "Si" No
Para continuar responde "Si" 10
Para continuar responde "Si" si
Para continuar responde "Si" Si
>>>

Vemos que el programa repite la misma secuencia hasta que introduzcamos la respuesta "Si", y también vemos que hay que introducirla exáctamente como está, con la "S" mayúscula y la "i" minúscula. También vemos una novedad en la cadena del prompt. Hemos escrito dos veces la secuencia de caracteres <\"> y ha sido interpretada como el caracter <"> en la salida. De hecho, dentro de una cadena de caracteres no podemos usar las comillas, porque se consideraría que eso termina la cadena de caracteres y produciría errores o resultados inesperados. Para eso usamos el caracter barra invertida o barra-atrás (backslash), que se interpreta como el comienzo de una secuencia de escape. El caracter a continuación de la barra invertida adquiere un significado diferente, lo cual nos permite introducir caracteres que no se pueden teclear o que tendrían un significado especial de no hacerlo así. Algunas secuencias de escape son las siguientes:

Secuencia Resultado Descripción Ejemplo
\\ \ Barra invertida "C:\\Windows\\System32" C:\Windows\System32
\" " Comillas dobles "Responda \"Si\" o \"No\":" Responda "Si" o "No":
\' ' Comilla sencilla 'Responda \'Truco\' o \'Trato\':' Responda 'Truco' o 'Trato':
\n Nueva línea 'Primero\nSegundo' Primero
Segundo
\N{name} Caracter Unicode
de nombre name
"\N{tilde}" ~
\uxxxx Caracter Unicode
con código xxxx
"\u00A9" ©
\ooo Caracter con código
octal ooo
"\41" !
\xhh.. Caracter con código
hexadecimal hh..
"\xBC" ¼

Vemos algunos conceptos nuevos como el de nombres y códigos de caracteres unicode, y códigos octales y hexadecimales. Más adelante ahondaremos en estos temas. Vamos a ver la segunda posibilidad de crear bucles mediante la palabra reservada for. Un bucle for está diseñado en Python para recorrer una secuencia de datos y trabajar uno por uno sobre ellos. La sintaxis del bucle for es:

for variable in iterador:

El bucle for trabaja extrayendo datos uno a uno del iterador (de momento nos basta con saber que cualquier secuencia es iterable y va devolviendo sus elementos) y los guarda en la variable de nombre indicado, que a cada vuelta asume el nuevo valor. A partír de aquí definiremos un bloque de código para trabajar sobre dichos valores mediante una secuencia de líneas indentadas. Normalmente usamos nombres cortos de variables, teniendo en cuenta que el valor va a ser sobreescrito una y otra vez, del tipo x, y, z, o i, j, o n para un valor numérico, o c para indicar que trabajamos con caracteres. Veamos un ejemplo:

texto="Con cien cañones por banda"

for c in texto:
print(c, end="_")

El resultado sería el siguiente:

============= RESTART: C:/Users/User/Documents/Python/For.py =============
C_o_n_ _c_i_e_n_ _c_a_ñ_o_n_e_s_ _p_o_r_ _b_a_n_d_a_

Podemos usar la función reversed() para invertir el orden de la secuencia:

texto="Con cien cañones por banda"

for c in reversed(texto):
print(c, end="")

De este modo obtendríamos la cadena del revés:

============= RESTART: C:/Users/User/Documents/Python/For.py =============
adnab rop senoñac neic noC

Por supuesto podemos también trabajar con tuplas o listas:

lista=[10,20,30,40,50]
suma=0

for n in lista:
suma+=n

print(suma)

El resultado, por supuesto, es este:

============= RESTART: C:/Users/User/Documents/Python/For.py =============
150

Un uso más interesante podría ser para inicializar una lista de valores:

lista=[]

for n in range(10):
lista.append(n)

print(lista)

Cuyo resultado es:

============= RESTART: C:/Users/User/Documents/Python/For.py =============
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

En este código hay dos cosas remarcables, en primer lugar el uso de la función range(). Se trata de una función muy adecuada para utilizarse en bucles, que genera una secuencia numérica en forma de progresión aritmética. Podemos usar hasta tres argumentos al llamar a range(), la sintaxis general es:

range(start, end, step)

Donde start sería el valor inicial, end el valor final (que como en el caso de las porciones no se llega nunca a alcanzar) y step el incremento entre un valor y el siguiente.

>>> #range() con un solo argumento, empieza en 0 hasta el entero inferior al argumento
>>> for n in range(10):
print(n, end=" ")

0 1 2 3 4 5 6 7 8 9

>>> #range() con dos argumentos, empieza en el primer valor hasta el entero inferior al segundo
>>> for n in range(95,105):
print(n, end=" ")

95 96 97 98 99 100 101 102 103 104

>>> #range() con tres argumentos; empieza en start
>>> # termina en el entero inmediatamente anterior a end
>>> # el tercer valor es el intervalo entre resultados sucesivos
>>> for n in range(0,21,5):
print(n, end=" ")

0 5 10 15 20

>>> for n in range(10,-1,-1):
print(n, end=" ")

10 9 8 7 6 5 4 3 2 1 0

Podemos usar incrementos negativos para contar hacia atrás. Si introducimos valores incongruentes (por ejemplo end < start con un incremento positivo) simplemente se devuelve un iterador vacío. Si lo usamos en un bucle no se ejecutará el bloque de sentencias en ningún momento.

>>> for i in range(10,1):
print("Este bucle no se ejecuta")

>>>

La otra cosa novedosa en el programa anterior es el uso de un método de los objetos de tipo lista: lista.append(). No vamos a ahondar en ello, pero Python es un lenguaje fuertemente orientado a objetos. Los objetos poseen propiedades, que son valores del tipo que podemos almacenar en una variable, y métodos, que son funciones que operan sobre el propio objeto. Accedemos a ellos usando la notación:

nombre_de_objeto.propiedad
nombre_de_objeto.método(posibles argumentos)

Vemos que los métodos usan la conocida notación de cualquier otra función, es decir, van seguidos de unos posibles argumentos entre paréntesis, o de unos paréntesis vacíos si no se requieren argumentos. Uno de los métodos de los objetos de clase lista es append(valor), que debe incluir un argumento. El argumento es añadido al final de la lista. En el capítulo acerca de las listas veremos todos sus métodos.

Naturalmente podemos anidar bucles, así como incluir bloques condicionales dentro de un bucle. Un ejemplo de bucles anidados:

# Bucles anidados
# Inicializamos una matriz bidimensional con los números 1 a 100

lista=[] # Creamos una lista vacía

# Rellenamos cada fila con otra lista y esta con los valores
for i in range(10):
lista.append([])
for j in range(10):
lista[i].append(10*i+j+1)

# Imprimimos el resultado por filas
for i in lista:
print(i)

Pulsamos F5 y este es el resultado

============= RESTART: C:/Users/User/Documents/Python/Bucles anidados.py =============
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
[51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
[61, 62, 63, 64, 65, 66, 67, 68, 69, 70]
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80]
[81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
[91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
>>>

Y un ejemplo de condicional anidado en un bucle:

# Primos.py
# Obtenemos una lista de números primos hasta un valor dado

valor=int(input("Introduce un número natural: "))

primos=[]

for i in range(2,valor+1):
if primos==[]:
primos.append(i)
else:
for j in primos:
if i%j==0:
break
else:
primos.append(i)

print(primos)

Vemos que tenemos condicionales anidados en un bucle, y otro bucle anidado en el condicional. Este codigo obtiene los valores primos hasta un número que introduce el usuario en la línea 4. Vamos guardando los valores en la variable primos de tipo lista. Cuando la lista está vacía añadimos el primer valor, que siempre será 2 en la primera vuelta del bloque for que empieza en la línea 8. A partir de ahí, para cada nuevo valor miramos si es divisible entre los valores primos ya obtenidos, y si no es así lo añadimos a la lista en la línea 16. Hay dos novedades, la sentencia break de la línea 14 interrumpe el bucle activo y sale de él. La clausula else en la línea 15 se ejecuta si el bucle realiza todas las iteraciones, esto quiere decir que si salimos del bucle a causa de la sentencia break no se ejecutará el bloque del else correspondiente. Veamos un ejemplo del resultado de nuestro programa:

============= RESTART: C:/Users/User/Documents/Python/Primos.py =============
Introduce un número natural: 40
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
>>>

Como acabamos de ver, los bucles pueden tener una cláusula else. El bloque que comprende dicha cláusula se ejecutará despues de la terminación normal del bucle, es decir, después de completar todas las iteraciones. Hay dos sentencias que alteran la ejecución del bucle; una acabamos de verla, es la sentencia break que provoca la terminación inmediata del bucle. Si hay un bloque else no será ejecutado. La otra es la sentencia continue. Esta interrumpe la ejecución del resto del bucle saltando al comienzo de este para el siguente valor de la iteración.

# Este bucle imprime solo números impares

for x in range(10):
if x%2==0:
continue
print(x)
else:
print("Programa terminado")

Pulsa F5

============= RESTART: C:/Users/User/Documents/Python/Continue.py =============
1
3
5
7
9
Programa terminado
>>>

No es necesario usar una sentencia else despues de continue, puesto que si se cumple la condición de la línea 4 y se ejecuta continue ninguna sentencia posterior se ejecuta en esa vuelta del bucle. La sentencia else de la línea 7 está emparejada con el for de la línea 3 y se ejecuta con normalidad al final del bloque for de las líneas 3-6.

Dejamos por el momento lo relativo a los bucles hasta una revisión exhaustiva más adelante y vamos a pasar a otra de las estructuras fundamentales de control de flujo: las funciones.

1.2.4 Funciones

Ya llevamos tiempo usando funciones, y sabemos que son identificadores que van seguidos por paréntesis y entre estos puede haber o no un número variable de argumentos. Las funciones que hemos usado hasta ahora son algunas de las funciones incorporadas directamente al intérprete, pero uno de los mecanismos de programación más potentes del que podemos disponer es la creación de nuestras propias funciones. Para esto usamos la palabra reservada def seguida del identificador elegido como nombre de función y luego los imprescindibles paréntesis con la lista de valores que la función puede aceptar. Dichos valores reciben el nombre de parámetros en la definición de la función y de argumentos en la llamada a esta. A continuación los habituales dos puntos y un bloque indentado de código que realiza el trabajo de la función.

def nombre_de_función (Parámetro_1, ... , Parámetro_n):
<Bloque de sentencias>
...

Para ver un ejemplo, podemos convertir en función el programa para calcular números primos, de forma que nos indique si un valor dado es primo o no.

#Función primo(x) - Nos devuelve True si x es primo y False en caso contrario

def primo(x):

primos=[]

for i in range(2,x+1):
if primos==[]:
primos.append(i)
else:
for j in primos:
if i%j==0:
break
else:
primos.append(i)

return x in primos

# Aquí termina la definición de la función

x=int(input("Número: "))

if primo(x):
print(x,"es primo")
else:
print(x,"no es primo")

Un par de vueltas de nuestro programa darían el siguiente resultado:

============= RESTART: C:/Users/User/Documents/Python/Función primo.py =============
Número 19
19 es primo
>>>
============= RESTART: C:/Users/User/Documents/Python/Función primo.py =============
Número 68
68 no es primo
>>>

Las funciones suponen un ahorro considerable de esfuerzo, tiempo y líneas de código, pues una vez creada una función podemos utilizarla cuantas veces queramos dentro de nuestro programa, e incluso en otros programas utilizando el mecanismo de importación de módulos que veremos en la siguiente sección.

Los identificadores utilizados para nombrar las funciones siguen las mismas normas que los nombres de variables. Igualmente conviene elegir nombres significativos, es mejor llamar a nuestra función primo() o esPrimo() que p(). En programas cortos, como los ejemplos hasta el momento, podemos ver de un solo vistazo todo el código y la definición de la función está muy cerca de su invocación, pero en programas con miles de líneas de código (y cualquier proyecto importante está en ese rango) y con múltiples ficheros, es mejor que los nombres de las cosas nos recuerden lo que hacen. Esto también es aplicable a los nombres de parámetros en la definición de la función. Hemos llamado x al parámetro de la función primo(x) y eso es válido para variables numéricas en general, pero sería más clarificador especificar mendiante el nombre que esperamos un número entero positivo (un número natural) como argumento en la llamada.

Otro aspecto importante que hasta ahora estamos dejando de lado es la comprobación de errores. Si en la línea 21 del código anterior el usuario introduce un texto que no representa un número entero, al aplicar la función int(input()) se produciría un error y el programa se abortaría. Asimismo en la función primo() no comprobamos si el argumento se corresponde con el tipo de dato y el rango de valores adecuados. Como estamos aprendiendo a crear funciones podemos diseñar una función que compruebe que el usuario introduce un valor entero válido.

# input_int() - Una función para introducir números enteros

def input_int(prompt="Introduce un número entero: "):

while True:
valor=input(prompt)
if valor.isdecimal():
return int(valor)
prompt="Debes introducir un valor entero: "

x=input_int()
print(x, type(x))

Vamos a comentar los nuevos aspectos antes de ejecutar el programa. En la línea 3 creamos la función input_int, observa que el nombre del parámetro indica perfectamente su función, y que hemos asignado un valor a dicho parámetro. Esto es un parámetro por defecto. Podemos invocar la función con un argumento, en cuyo caso la variable local prompt tomará el valor de dicho argumento, pero también podemos invocarla sin ningún argumento (como de hecho hacemos en la línea 12) y entonces prompt adoptará el valor que hemos asignado en la definición de la función.

Como tenemos que insistir hasta que el usuario complazca nuestros requerimientos hay que crear un bucle, y eso se realiza en la línea 5. Observa que while True: crea un bucle infinito. La condición del bucle siempre se cumple, así que para salir de él hemos de usar alguno de los métodos alternativos, como la sentencia break. En este caso la salida se produce en la línea 8, cuando la entrada del usuario es correcta la convertimos en un valor int y la enviamos de retorno con una sentencia return. Como en este momento salimos de la función dejamos de dar vueltas al bucle.

En la línea 7 usamos un método de la clase string, el método cadena.isdecimal(), siendo cadena un objeto de clase str que devuelve True si todos los caracteres de cadena representan dígitos del 0 al 9, y si hay al menos un caracter. Por útimo, si se produce una entrada incorrecta, modificamos el prompt en la línea 10 para hacérselo ver al usuario. Si lo ejecutamos este puede ser un ejemplo del resultado:

============= RESTART: C:/Users/User/Documents/Python/input_int.py =============
Introduce un número entero: diez
Debes introducir un valor entero: 10.0
Debes introducir un valor entero: -10
Debes introducir un valor entero: 10
10 <class 'int'>

Vemos que la función funciona bastante bien, la insistencia del prompt puede resultar un tanto maquinal, y hay un fallo sustancial que es la falta de reconocimiento del signo negativo. Si quisiéramos ser aún más sofisticados podríamos aceptar el valor float cuando los decimales sean 0. Vamos a resolver el asunto del signo y de paso podemos dar un poco de variedad a los requerimientos de la máquina, la cuestión de aceptar valores float sin parte decimal es un buen ejercicio para el lector.

# input_int() - Versión con signo

def input_int(prompt="Introduce un número entero: "):

prompts=["Introduce un número entero: ",
"Debes introducir un valor entero: ",
"Solo acepto un número entero válido: ",
"Haz el favor de teclear un entero correcto: ",
"Mi paciencia tiene un límite: "
]
c=0

while True:
c+=1
if (valor:=input(prompt))!="" and valor!="-":
if valor[0]!="-" and valor.isdecimal() or \
valor[0]=="-" and valor[1:].isdecimal():
return int(valor)
prompt=prompts[c%5]

x=input_int()
print(x, type(x))

Dentro de la función en las líneas 5-11 definimos unas variables locales con una lista de frases para utilizar de prompt y un contador para movernos a lo largo de dicha lista. Observa cómo hemos colocado los valores dentro de la lista prompts, las normas de estilo de Python requieren líneas de un máximo de 79 carateres. Si definimos listas de valores largas podemos separar los valores en las comas entre elementos en líneas diferentes. Esta es una de las pocas situaciones en que podemos prolongar una sentencia entre líneas, más adelante aprenderemos otros sistemas para lograrlo. En la línea 14 incrementamos el contador cada vuelta del bucle.

En la línea 15 hemos usado una nueva forma del operador de asignación. El operador normal (el signo =) no devuelve ningún valor, y por lo tanto no puede emplearse dentro de una expresión, pero a partir de la versión 3.8 del lenguaje se ha incorporado una nueva forma de asignación que devuelve el valor asignado y por tanto puede ser empleada dentro de cualquier expresión. La nueva forma consiste en los caracteres dos puntos seguido del símbolo de igualdad :=. De esta manera asignamos el resultado de la función input() a la variable valor y a la vez comprobamos que no es una cadena vacía. Si no envolviésemos en paréntesis la expresión: valor:=input(prompt) primero se ejecutaría la comparación input(prompt)!="" y el resultado (o sea, el valor False si la entrada es una cadena vacía o el valor True en caso contrario) se asignaría a la variable valor, que evidentemente no es lo que queremos hacer. Una vez comprobado que tenemos una respuesta que no es "" se evalúa la condición después del operador and, y comprobamos que no hemos tecleado solamente el signo -.

Una vez comprobados estos dos aspectos, en la línea 16 hacemos unas cuantas comprobaciones en cadena. Como el operador and tiene más prioridad que el or se evaluarán primero los dos grupos relacionados mediante aquel. Por cierto, aquí ves otra forma de dividir una línea larga, usamos el caracter barra invertida al final de la línea. El código de estilo de Python indica que debemos alinear las expresiones para favorecer la legibilidad. Por cierto, en la definición de la lista prompts también es correcto alinear los valores de la lista, en esta caso las comillas de las cadenas de texto. Comprobamos si hay un caracter con el signo - al comienzo de la cadena, si no lo hay comprobamos que toda la cadena está compuesta de dígitos 0-9 y si lo hay comprobamos a partir de la posición de índice 1, o sea, el caracter después del signo -. Una buena experiencia sería añadir la opción de utilizar un signo + al comienzo del número, desde aquí te sugiero que pienses en cómo se haría. Si la variable valor pasa todas las pruebas la convertimos en número entero y devolvemos este.

Por último, en la línea 19 vamos cambiando el prompt entre los 5 valores disponibles, usamos la función módulo con el contador para obtener un resultado entre 0 y 4. Después de esta larga disertación lancemos el programa.

============= RESTART: C:/Users/User/Documents/Python/input_int 2.py =============
Introduce un número entero: diez
Debes introducir un valor entero: 10.0
Solo acepto un número entero válido: 20-10
Haz el favor de teclear un entero correcto: -
Mi paciencia tiene un límite:-10
-10 <class 'int'>

Vemos que hemos conseguido ampliar el rango a todos los enteros, incluídos los valores negativos, y que resulta mucho más estimulante para el usuario una respuesta más variada 😜

Hemos visto que algunas funciones, como nuestra amiga print(), pueden aceptar una cantidad indeterminada de parámetros, vamos a ver cómo definir nuestras funciones para poder hacer lo mismo. El truco está en utilizar un asterisco antes del nombre del parámetro, veámoslo en acción.

# múltiple() - Un ejemplo de empleo de múltiples argumentos en una función

def múltiple(*arg):
print(f"arg={arg}")
print(f"type(arg)={type(arg)}")
print(f"len(arg)={len(arg)}")

múltiple(1)
print()
múltiple(1,(2,3))
print()
múltiple(False,1,"Hola")

Al ejecutar nuestro programa vemos qué ocurre con los argumentos que enviamos a la función múltiple().

============= RESTART: C:/Users/User/Documents/Python/Múltiple.py =============
arg=(1, )
type(arg)=<class 'tuple'>
len(arg)=1

arg=(1, (2, 3))
type(arg)=<class 'tuple'>
len(arg)=2

arg=(False, 1, 'Hola')
type(arg)=<class 'tuple'>
len(arg)=3
>>>

La clave está en que los argumentos son enviados en una tupla. Podemos comprobar la longitud de dicha tupla y evaluar cada argumento mediante un bucle. Podemos mezclar ambos modos de enviar argumentos, primero colocaremos los argumentos normales y luego utilizaremos un asterisco para indicar múltiples argumentos, una vez leídos los argumentos iniciales, el resto se colocan en una tupla como acabamos de ver. Vamos a verlo en acción:

# resta() - Una función para restar sobre un valor inicial

def resta(x, *arg)
for n in arg:
x-=n
return x

print(resta(100))
print(resta(100,90))
print(resta(100,10,20,30))

Pulsamos F5 para ejecutarla, guardándola anter como resta.py

============= RESTART: C:/Users/User/Documents/Python/resta.py =============
100
10
40

El primer argumento es obligatorio, si no enviamos más se devuelve el propio valor. Todo lo que enviemos a continuación es restado del total inicial y se devuelve el resultado. Hay una tercera forma de enviar valores, que es mediante nombres, pero la dejaremos pendiente hasta que estudiemos los diccionarios.

Con esto tenemos una idea inicial de cómo crear nuestras propias funciones. Vamos a ver a continuación parte del inmenso repertorio de funciones que el lenguaje incluye con la instalación del intérprete, y el método para ampliar aún más dicho repertorio.

1.2.5 Módulos

El intérprete trae una serie de funciones incorporadas, lo que se denomina en inglés: built-in. Hasta ahora estamos utilizando dichas funciones como print(), type(), etc. También hemos visto cómo definir funciones a medida, pero vamos a conocer una poderosa herramienta que nos abre un mundo de posibilidades, la importación de módulos.

Un módulo, sencillamente, es un fichero .py con sentencias Python. Podemos definir todas nuestras funciones en un fichero y llamarlo (por ejemplo) misFunciones.py. A partir de este momento, si utilizamos la sentencia import misFunciones en cualquier programa se cargará y ejecutará el fichero, con lo cual dispondremos de todas nuestras funciones particulares en el resto de nuestro código. Sucede que la distribución de Python incluye numerosos módulos organizados en paquetes (packages), de forma que podemos disponer de miles de funciones especializadas para todo tipo de tareas. Vamos a ver un primer ejemplo:

# Import_1 - Nuestro primer módulo importado

import keyword

for k in keyword.kwlist:
print(k)

print("-"*10, keyword.iskeyword("False"), "-"*10)

El módulo keyword tiene solamente el atributo kwlist que es una lista de todas las palabras reservadas, y el método iskeyword() que devuelve True si la cadena que pasamos como argumento corresponde con una palabra reservada. Ejecuta el programa para obtener la lista de todas la palabras reservadas de tu versión de Python, y para comprobar que False es una de ellas. Lo importante es que estamos cargando funciones externas en nuestro programa. Te habrás fijado en que para referirnos al atributo y al método mencionados necesitamos usar la notación keyword.kwlist y keyword.iskeyword(). Cuando importamos un módulo con la sintaxis que acabamos de emplear este es el comportamiento por defecto. Podemos usar una sintaxis alternativa para emplear un alias más manejable que el nombre del módulo.

# Importar módulos usando alias

import keyword as kw

for k in kw.kwlist:
print(k)

print("-"*10, kw.iskeyword("False"), "-"*10)

Esto es mucho más práctico si el nombre del módulo es largo y usamos muchas funciones de dicho módulo. Aún hay otra forma de emplear la sentencia import que carga directamente todos los valores y funciones definidos en el módulo sin necesidad de referirnos a este. En general no se recomienda esta forma debido a que pueden producirse conflictos con nombres ya existentes, pero con el módulo keyword no hay ese peligro.

# Importar directamente el contenido del módulo

from keyword import *

for k in kwlist:
print(k)

print("-"*10, iskeyword("False"), "-"*10)

Si en vez de * hubiéramos empleado un identificador de una función o valor, solamente se importaría dicha función o valor. Podemos emplear una serie de identificadores separados por comas, para los que también podríamos emplear alias.

# Importar parcialmente el contenido del módulo

from keyword import kwlist, iskeyword

for k in kwlist:
print(k)

print("-"*10, iskeyword("False"), "-"*10)

Con esto ya conocemos todas las posibilidades de importación. La distribución de Python en Windows incluye por defecto todos los módulos que componen la biblioteca estándar del lenguaje. Aquí puedes encontrar (la mayoría de la información en inglés) la referencia completa de dicha biblioteca:

Python 3.8.5. Biblioteca estándar.

Si la bibloteca estándar no satisface nuestras necesidades, tenemos un inmenso repositorio de módulos en Python Package Index (PyPI) De momento exploremos algunas posibilidades de los paquetes incorporados por defecto y luego veamos cómo descargarlos de PyPI

El módulo math incluye numerosas funciones matemáticas. Repasaremos una muestra de ellas.

# Algunas funciones del módulo math

import math

# La función presenta nos muestra la función a evaluar y su resultado
def presenta(descripción,función,valor):
expresión="math."+función+"("+str(valor)+")"
print(f"{descripción}:<30}: {expresión}={eval(expresión)}")

ejemplos=(("Redondeo hacia arriba","ceil",10.55),
("Redondeo hacia abajo","floor",10.55),
("Eliminación de decimales","trunc",10.55),
("Suma de varios valores","fsum",[.1,.1,.1,.1,.1]),
("Factorial","factorial",5),
("Máximo común divisor","gcd","20,50"),
("Logaritmo natural","log","math.e"),
("Logaritmo en base 2","log2",32),
("Logaritmo en base 10","log10",1000),
("Potencia","pow","5,5"),
("Raíz cuadrada","sqrt",36),
("Radianes","radians",180),
("Grados","degrees","math.pi"),
("Seno","sin","math.radians(90)"),
("Coseno","cos",0),
("Tangente","tan","math.radians(45)")
)

for item in ejemplos:
presenta(item[0],item[1],item[2])

Creamos la función presenta() que nos permite mostrar una descripción de cada función, la invocación de dicha función y el resultado de dicha invocación. En la línea 7 componemos la expresión a evaluar concatenando el nombre de la librería (math) seguido por un punto, el nombre de la función y los argumentos entre paréntesis. Empleamos una cadena con formato en la línea 8 para mostrar toda la información. La cadena empieza con una f justo antes de las comillas, el contenido de estas se muestra como una cadena normal salvo los campos entre llaves { }, que son evaluados como expresiones Pyhton y se muestra el resultado obtenido.

El primer campo es el primer argumento, que contiene una cadena de texto con la descripción de la función, se muestra dicha cadena y vemos que después del nombre del argumento hay un caracter dos puntos seguido del caracter menor-que y una cifra. Esto es una especificación de formato, el campo se presenta justificado a la izquierda (<) en un bloque de 30 espacios. El caracter dos puntos a continuación está fuera de las llaves, por lo cual se muestra tal cual. Luego presentamos la cadena con la llamada a la función que hemos compuesto en la línea anterior, seguida del signo = y de una expresión novedosa. Usamos la función eval() con la llamada a función. La función eval() recibe una cadena de caracteres y la evalúa como si fuese una expresión en Python, devolviendo el resultado. Tenemos dos expresiones seguidas {expresión} y {eval(expresión)}, que se parecen pero son muy diferentes. La primera expresión es una cadena de caracteres literal, y como vimos en las secciones sobre el intérprete interactivo, se evalúa devolviendo la propia cadena. En cambio, la segunda llama a la función eval() pasando como argumento la cadena, con lo cual la cadena es interpretada como si fuera una instrucción Python (de hecho es lo que es).

Para entenderlo mejor, ejecuta el programa y este es el resultado:

============= RESTART: C:/Users/User/Documents/Python/math test.py =============
Redondeo hacia arriba: math.ceil(10.55) = 11
Redondeo hacia abajo: math.floor(10.55) = 10
Eliminación de decimales: math.trunc(10.55) = 10
Suma de varios valores: math.fsum([0.1, 0.1, 0.1, 0.1, 0.1]) = 0.5
Factorial: math.factorial(5) = 120
Máximo común divisor: math.gcd(20,50) = 10
Logaritmo natural: math.log(math.e) = 1.0
Logaritmo en base 2: math.log2(32) = 5.0
Logaritmo en base 10: math.log10(1000) = 3.0
Potencia: math.pow(5,5) = 3125.0
Raíz cuadrada: math.sqrt(36) = 6.0
Radianes: math.radians(180) = 3.141592653589793
Grados: math.degrees(math.pi) = 180.0
Seno: math.sin(math.radians(90)) = 1.0
Coseno: math.cos(0) = 1.0
Tangente: math.tan(math.radians(45)) = 0.9999999999999999
>>>

La primera línea azul nos muestra la función ceil() del módulo math que redondea hacia arriba un valor flotante convirtiéndolo en entero. La expresión que hemos compuesto es: "math.ceil(10.55)", y el resultado al ejecutar eval("math.ceil(10.55))" es el valor entero 11. Hay una equivalencia línea a línea entre los resultados mostrados y el contenido de la tupla ejemplos, que se define en las líneas 10-26.

Otro módulo de la librería estándar relacionado con las matemáticas es random, que incluye funciones para obtener resultados aleatorios.

Algunas funciones del módulo random
random() Devuelve un valor flotante x tal que: 0.0<=x<1.0
uniform(float1,float2) Devuelve un valor flotante x tal que float_min<=x<float_max
siendo float_min el menor de los dos argumentos y float_max el mayor
randrange(integer) Devuelve un valor entero x tal que 0<=x<integer
randrange(start,end,step) Devuelve un valor entero x tal que start<=(x=(start+n*step))<end
(Los argumentos de randrange() funcionan como los de range())
choice(secuencia) Devuelve uno de los valores de secuencia
shuffle(secuencia) Baraja (ordena al azar) el contenido de secuencia
La secuencia tiene que ser de tipo mutable
sample(secuencia,k) Devuelve una selección de k elementos de secuencia sin repetir

Probemos algunos ejemplos de estas funciones:

>>> import random
>>> random.random()
0.3987917666805235
>>> random.uniform(100,1000)
514.291456849425
>>> random.randrange(10)
2
>>> random.randrange(100,1001,50)
400
>>> lista=["uno","dos","tres","cuatro","cinco","seis"]
>>> random.shuffle(lista)
>>> lista
['uno', 'seis', 'cuatro', 'tres', 'cinco', 'dos']
>>> random.sample(lista,3)
['uno', 'dos', 'cinco']
>>>

Fíjate en que la función random.shuffle() no devuelve ningún valor, la lista es barajada en si misma, por eso se requiere una secuencia mutable. Si lo intentamos con una secuencia no mutable obtendremos un error:

>>> lista=("uno","dos","tres","cuatro","cinco","seis")
>>> random.shuffle(lista)
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
random.shuffle(lista)
File "C:\Users\Miguel\AppData\Local\Programs\Python\Python38\lib\random.py", line 307,
in shuffle
x[i], x[j] = x[j], x[i]
TypeError: 'tuple' object does not support item assignment

Mirando la información del error de abajo hacia arriba, vemos que el error es que un objeto de clase tuple no soporta la asignación de valores (puesto que es inmutable). El error se produce en la sentencia que trata de intercambiar dos valores entre sí, en la función shuffle, concretamente en la línea 307 del módulo random.py cuyo directorio nos muestra también. Continuando hacia arriba vemos que el error viene desde la instrucción random.shuffle(lista) que está en la línea uno de nuestro programa porque estamos en modo interactivo. La información de los errores detalla toda la cadena de llamadas que ha provocado el error, y a partir de ella podemos saber con bastante precisión de donde viene el fallo. Ya que estamos en ello, IDLE tiene una opción en el menú File que es Open Module. Si la usamos e introducimos el nombre random en la ventana que se abre podemos indagar el código del propio módulo. Si vas a la línea 307 verás justamente la sentencia que intercambia valores dentro de la definición de la función shuffle().

Los valores aleatorios (en realidad pseudo-aleatorios, puesto que dependen de un algoritmo) son muy importantes en programación. Concretamente, pocos juegos podrían programarse si no hubiese un grado de aleatoriedad, y más adelante los emplearemos profusamente para crear simulaciones estadísticas. Dejamos aquí el módulo random y vamos a un mundo completamente diferente, el de los juegos de caracteres.

Ya vimos en la sección Bucles algunas secuencias de escape que hacían referencia a códigos unicode. El ordenador es una máquina para la cual TODO son números. Con los textos ocurre lo mismo, para que podamos ver un texto en pantalla o impreso, o introducirlo desde el teclado, se utilizan valores numéricos que se corresponden con las letras y símbolos de escritura. Hay distintos conjuntos de caracteres identificados por distintas colecciones de valores. Durante mucho tiempo, en un mundo de bytes de ocho bits, capaces de representar números del 0 al 255, se usaba un conjunto de caracteres de ese tamaño como máximo, y se les asignaban los valores que pueden guardarse en un solo byte. El código ASCII era el más empleado, pero con la llegada de interfaces gráficos y de máquinas de 16, 32 y actualmente 64 bits, se plantearon otros sistemas de representación, hasta llegar al unicode, que pretende ser una forma universal de representar cualquier sistema de escritura de la humanidad. De hecho hay posibilidades de representar 1.114.112 valores distintos.

La librería unicodedata proporciona funciones para manejar los caracteres Unicode. Vamos a explorar algunas de sus posibilidades.

# Unicode - Prácticas con los caracteres de texto

import unicodedata as ud

start=eval(input("Start: "))
print(start)
end=eval(input("End: "))
print(end)

print("f"\nUnicode versión: {ud.unidata_version}\n"")

for c in range(start,end+1):
ch=chr(c)
print(f"{c:04} 0x{c:04X} - {ch} - {ud.name(ch,'')} - {ud.category(ch)}")

Importamos la librería en la línea 3 con un alias (esto es recomendable para librerías con nombres tan largos), pedimos al usuario que introduzca un rango de valores en las líneas 5 a 8, luego mostramos la versión de unicode que maneja nuestro Python (empleando el valor unidata_version de la biblioteca), e imprimimos una serie de campos para cada código en el rango elegido.

Los campos son el valor en decimal y en hexadecimal de los códigos que representan los caracteres, luego el caracter en sí, obtenido en la línea 13 con la función chr(c), seguido por su nombre dentro de la librería unicode y su categoría indicada mediante códigos de dos letras. Para estas últimas informaciones usamos las funciones name() y category() de la biblioteca. Observa que un valor no lleva paréntesis a continuación, solo el identificador, en cambio para invocar funciones son imprescindibles. Ejecuta el código con los siguientes números:

============= RESTART: C:/Users/User/Documents/Python/Unicode.py =============
Start: 97
97
End: start+25
122

Unicode versión: 12.1.0

0097 0x0061 - a - LATIN SMALL LETTER A - Ll
0098 0x0062 - b - LATIN SMALL LETTER B - Ll
0099 0x0063 - c - LATIN SMALL LETTER C - Ll
0100 0x0064 - d - LATIN SMALL LETTER D - Ll
0101 0x0065 - e - LATIN SMALL LETTER E - Ll
0102 0x0066 - f - LATIN SMALL LETTER F - Ll
0103 0x0067 - g - LATIN SMALL LETTER G - Ll
0104 0x0068 - h - LATIN SMALL LETTER H - Ll
0105 0x0069 - i - LATIN SMALL LETTER I - Ll
0106 0x006A - j - LATIN SMALL LETTER J - Ll
0107 0x006B - k - LATIN SMALL LETTER K - Ll
0108 0x006C - l - LATIN SMALL LETTER L - Ll
0109 0x006D - m - LATIN SMALL LETTER M - Ll
0110 0x006E - n - LATIN SMALL LETTER N - Ll
0111 0x006F - o - LATIN SMALL LETTER O - Ll
0112 0x0070 - p - LATIN SMALL LETTER P - Ll
0113 0x0071 - q - LATIN SMALL LETTER Q - Ll
0114 0x0072 - r - LATIN SMALL LETTER R - Ll
0115 0x0073 - s - LATIN SMALL LETTER S - Ll
0116 0x0074 - t - LATIN SMALL LETTER T - Ll
0117 0x0075 - u - LATIN SMALL LETTER U - Ll
0118 0x0076 - v - LATIN SMALL LETTER V - Ll
0119 0x0077 - w - LATIN SMALL LETTER W - Ll
0120 0x0078 - x - LATIN SMALL LETTER X - Ll
0121 0x0079 - y - LATIN SMALL LETTER Y - Ll
0122 0x007A - z - LATIN SMALL LETTER Z - Ll
>>>

AL utilizar la función eval() para convertir la entrada de texto, podemos permitirnos introducir el valor end en la forma en que lo hemos hecho. Vemos que los caracteres obtenidos son las letras minúsculas del alfabeto (en su versión inglesa). La categoría 'Ll' se refiere a letras minúsculas (Lower letters). Estamos en los dominios del antiguo código ASCII y se mantienen los mismos valores para proporcionar una cierta compatibilidad. Observa cómo se escribe un número hexadecimal en Python: un cero y el caracter x seguidos por el valor del número. Como el sistema hexadecimal maneja dieciseis dígitos los códigos 0-9 se nos quedan cortos, así que utilizamos las letras a-f para representar los dígitos 10 a 15. La distribución del juego de caracteres ASCII y en cierta medida del unicode, está mejor acomodada si pensamos en los valores hexadecimales. Por ejemplo, las letras mayúsculas están en las posiciones 0x0041 hasta 0x005A. Vemos que hay un paralelismo con las minúsculas. Prueba a introducir dichos valores en otra ejecución del programa. La categoría obtenida es 'Lu' de letras mayúsculas (Upper letters).

Los primeros 32 valores (del 0 al 31, el 32 es el espacio) corresponden a códigos de control. Si introduces el valor 0 para start y 32 para end obtendrás lo siguiente.

============= RESTART: C:/Users/User/Documents/Python/Unicode.py =============
Start: 0
0
End: 32
32

Unicode versión: 12.1.0

0000 0x0000 -
0001 0x0001 - ┃ -   - Cc
0002 0x0002 -   -   - Cc
0003 0x0003 - ┃ -   - Cc
0004 0x0004 - ┃ -   - Cc
0005 0x0005 - ┃ -   - Cc
0006 0x0006 - ┃ -   - Cc
0007 0x0007 - ┃ -   - Cc
0008 0x0008 - ┃ -   - Cc
0009 0x0009 -    -  - Cc
000A 0x000A -
-  - Cc

000B 0x000B - ┃ -   - Cc
000C 0x000C - □ -   - Cc
000D 0x000D -   -   - Cc
000E 0x000E - ┃ -   - Cc
000F 0x000F - ┃ -   - Cc
0010 0x0010 - ┃ -   - Cc
0011 0x0011 - ┃ -   - Cc
0012 0x0012 - ┃ -   - Cc
0013 0x0013 - ┃ -   - Cc
0014 0x0014 - ┃ -   - Cc
0015 0x0015 - ┃ -   - Cc
0016 0x0016 - ┃ -   - Cc
0017 0x0017 - ┃ -   - Cc
0018 0x0018 - ┃ -   - Cc
0019 0x0019 - ┃ -   - Cc
001A 0x001A - ┃ -   - Cc
001B 0x001B - ┃ -   - Cc
001C 0x001C -   -   - Cc
001D 0x001D -   -   - Cc
001E 0x001E -   -   - Cc
001F 0x001F -   -   - Cc
0032 0x0020 -   -  SPACE - Zs
>>>

Los caracteres de control no son imprimibles, en cambio representan instrucciones para el dispositivo de visualización (que originalmente eran modelos de teletipo). Por ejemplo el caracter 9 es el <Tabulador>, que mueve el punto de escritura a la siguiente posición de tabulación, y el 10 es el <Salto de línea> que lo mueve a la siguiente línea (corresponde al caracter de escape "\n"). IDLE no reconoce la mayoría de los caracteres de control, si ejecutas el programa en la consola (añade un input() al final para ver el resultado) obtendrás lo siguiente:

Te propongo algunas zonas interesantes del juego Unicode para que explores por tu cuenta:

Posiciones
0x0400 0x04FF Caracteres cirílicos
0x0391 0x03FF Alfabeto griego
0x0600 0x06FF Alfabeto árabe
0x2300 0x23FF Símbolos técnicos
0x2190 0x21FF Flechas
0x2200 0x22FF Operadores matemáticos
0x25A0 0x25FF Formas geométricas
0x2500 0x257F Trazado de recuadros
0x2600 0x26FF Símbolos variados
0x1F680 0x1F6FF Símbolos de cartografía y transportes
0x1F600 0x1F64F Emoticonos

Terminamos con el asunto de los caracteres mencionando otro par de funciones útiles: unicodedata.lookup(nombre) devuelve el caracter de nombre==nombre, si existe, y en caso contrario produce un error. La función incorporada ord(caracter) devuelve el código numérico del caracter proporcionado como argumento.

El último módulo de la librería estándar que vamos a curiosear es time. Como puedes imaginarte incorpora funciones dedicadas a la gestión del tiempo. En el universo numérico del ordenador, el tiempo se cuenta de una forma peculiar, se utiliza la cantidad de segundos transcurridos desde un momento inicial (epoch). Este momento depende de la plataforma (PC, Mac, sistemas UNIX, etc.). Por ejemplo, para los sistemas UNIX el origen son las 00:00:00 UTC del 1 de enero de 1970. UTC quiere decir Tiempo universal coordinado En cualquier caso, el propio sistema se encarga de traducirnos las medidas temporales al calendario y el reloj reales.

Vamos a manejar tres conceptos fundamentales: los segundos desde el origen (epoch), la hora y fecha locales y la hora y fecha UTC. Veamos un pequeño programa:

# Biblioteca time

import time

print("Segundos dede epoch:",time.time())
print("Hora local:",time.asctime(time.localtime()))
print("Hora UTC:",time.asctime(time.gmtime()))

El resultado de la ejecución dependerá del momento en que la realices. Por ejemplo:

============= RESTART: C:/Users/User/Documents/Python/Biblioteca time =============
Segundos desde epoch: 1596238664.7555752
Hora local: Sat Aug 1 01:37:44 2020
Hora UTC: Fri Jul 31 23:37:44 2020
>>>

Hemos empleado cuatro funciones de la biblioteca. La más sencilla es time.time() que nos devuelve un número float con el número de segundos y fracciones de segundo transcurridos desde el epoch de nuestro sistema. Podemos emplear esta función para medir intervalos de tiempo, por ejemplo cronometrar el tiempo que un programa tarda en realizar una tarea. También hemos usado time.localtime() y time.gmtime() que nos devuelven respectivamente la hora local y la hora en tiempo UTC. El valor que devuelven estas funciones es una tupla con una serie de campos. Para convertirlos en una representación más adecuada empleamos la función time.asctime(struct_time). Vemos que nos presenta la información al modo anglosajón. Vamos a crear una función que nos la presente en perfecto Español.

# Mi tiempo - Un vistazo al módulo time

import time

días=("lunes","martes","miércoles","jueves","viernes","sábado","domingo")
meses=("enero","febrero","marzo","abril","mayo","junio","julio",
"agosto","septiembre","octubre","noviembre","diciembre")

def momento(T):
print(f"Son las {T.tm_hour}:{T.tm_min:02}:{T.tm_sec:02}h del {días[T.tm_wday]} "+\
f"{T.tm_mday} de {meses[T.tm_mon]-1} de {T.tm_year]"

momento(time.localtime())

La estructura struct_time que nos devuelve time.localtime() posee una serie de campos a los que accedemos indicando el nombre de la estructura y el del campo con un caracter punto entre ellos. Utilizamos una cadena de formato para mostrar los campos struct_time.tm_hour, struct_time.tm_min, struct_time.tm_sec, struct_time.tm_wday, struct_time.tm_mday, struct_time.tm_mon y struct_time.tm_year. Para los minutos y segundos establecemos un formato de un mínimo de dos cifras completando con ceros si es necesario: ":02". En el caso del día de la semana y del mes, utilizamos el número como índice de las tuplas días y meses (corrigiendo este último para movernos en un índice de 0 a 11) y así extraemos la cadena con el nombre del día de la semana y del mes, respectivamente. La ejecución de este programa produce un resultado similar al siguiente:

============= RESTART: C:/Users/User/Documents/Python/Mi tiempo.py =============
Son las 22:01:30h del lunes 3 de Agosto de 2020

Hasta aquí esta aproximación a la biblioteca estándar. Vamos a ver el modo de descargar más paquetes de módulos desde PyPI, el sitio oficial de internet donde la comunidad Python organiza los paquetes de librerías que se van desarrollando para ampliar el lenguaje. Para esto tenemos que manejar la consola del sistema Windows.

Si buscas en Cortana "command" o "consola" la primera opción que te saldrá será la que llama Símbolo del sistema. Esa es la consola de texto. Ejecútala y te aparecerá una pantalla en negro y un prompt que nos indica la unidad y directorio activos tras el que puedes teclear comandos.

Antes de la existencia de los interfaces gráficos, los ordenadores funcionaban en modo texto, en una pantalla que mostraba tan solo líneas de caracteres. Sistemas como el antiguo MS-DOS y los sistemas UNIX eran así, de hecho, los sistemas de la familia UNIX, como el LINUX que se puede instalar en un PC siguen estando basados en la consola de texto. El interfaz gráfico funciona como una capa que nos oculta las interioridades del sistema. La consola funciona en cierto modo como nuestro intérprete de Python, se teclean órdenes y la consola las cumple si son reconocidas. La mayor parte de las órdenes disponibles sirven para gestionar el sistema de ficheros, incluyendo la posibilidad de ejecutar los ficheros que contienen programas. Notros tenemos que ejecutar el programa PiP que corresponde al el Instalador de Paquetes de Python.

Teclea pip en la consola. Si incluíste el directorio del Python en el PATH del sistema obtendrás el siguiente resultado:

El programa te proporciona una excelente información de ayuda con las diversas opciones que puedes emplear. Vamos a aprender dos de ellas, por el momento. El comando install sirve para instalar paquetes, y con la opción --upgrade para actualizarlos. El comando list sirve para ver los paquetes instalados, y con la opción --outdated para ver aquellos que están desactualizados.

Prueba a teclear (en el símbolo del sistema) la orden:   pip install --upgrade pip

Si tu paquete pip está actualizado te saldrá (posiblemente después de unas comprobaciones por parte de tu antivirus) lo siguiente:

En caso contrario el programa actualiza el paquete requerido, que en este mismo caso es el propio instalador de paquetes. Cuando termine la actualización puedes usar la orden   pip list   para ver los paquetes instalados en tu sistema. Como mínimo te saldrá el propio paquete pip:

En mi caso, ya hay unos cuantos paquetes instalados 😜

Vamos a instalar un paquete externo que nos permite usar colores en la consola. El paquete se llama colorama y lo instalaremos mediante la orden:   pip install colorama   en la consola del sistema. Si todo va bien en unos instantes tendremos el paquete disponible para nuestro intérprete de Python. Edita el siguiente programa en IDLE y guárdalo pulsando CTRL-S.

# Prueba de colorama

from colorama import init
init()

from colorama import Fore,Back,Style
import sys
import os

def inIDLE():
return "idlelib" in sys.modules

#Extraemos la lista de colores de primer plano disponibles
fore=[eval("Fore."+i) for i in dir(Fore) if i[0]!="_" and i!="RESET"]
#Extraemos la lista de colores de fondo disponibles
back=[eval("Back."+i) for i in dir(Back) if i[0]!="_" and i!="RESET"]

colores=("NEGRO",
"AZUL",
"CYAN",
"VERDE",
"GRIS",
"AZUL CL",
"CYAN CL",
"VERDE CL",
"MAGENTA CL",
"ROJO CL",
"BLANCO CL",
"AMARILL CL",
"MAGENTA",
"ROJO",
"BLANCO",
"AMARILLO")

if inIDLE():
print("Este programa no funciona en IDLE")
else:
os.system("cls") #Borra la consola
print("Demostración de colorama:")
print("="*40+"\n")

#Imprimimos la cabecera de los colores de fondo
print(" "*11,end="")
for i,b in enumerate(back):
if==0:
print(Fore.WHITE+b+f"{colores[i]:<10}",end="")
else:
print(Fore.BLACK+b+f"{colores[i]:<10}",end="")

#Imprimimos todas las líneas con el color de texto sobre los distintos fondos
print()
for i, f in enumerate(fore):
if i==0:
print(f.Back.WHITE+f"{colores[i]:>10} ",end="")
else:
print(f+Back.BLACK+f"{colores[i]:>10} ",end="")
for b in back:
print(f+b+"0123456789",end="")
print(Style.RESET_ALL) #Reseteamos los colores de texto

Parece un programa un poco largo, pero sobre todo es por la declaración de la tupla colores, que ocupa 17 líneas. Si lo ejecutas en IDLE comprobarás que el resultado es:

============= RESTART: C:/Users/User/Documents/Python/Colorama_test.py =============
Este programa no funciona en IDLE
>>>

La función inIDLE() emplea la propiedad sys.modules de la librería sys para detectar si estamos en el entorno de ejecución de IDLE, y en caso afirmativo devuelve el valor True. En la línea 35 comprobamos si es así, en cuyo caso mostramos el mensaje y no ejecutamos más líneas, puesto que el resto de código pertenece a la cláusula else. Vamos a inspeccionar con más detalle el programa, que tiene varios aspectos que debes aprender.

Las líneas 3 a 8 contienen las importaciones de módulos. Del módulo colorama importamos cuatro propiedades, que incluyen la función init() y los objetos Fore, Back y Style, que contienen los códigos para cambiar el color de texto, el de fondo y el estilo del texto, respectivamente. Además, para resaltar el uso de init() la importamos en una línea separada e inmediatamente la ejecutamos, con lo cual la consola queda preparada para procesar las secuencias ANSI que sirven para cambiar los colores. En realidad son cadenas de caracteres que empiezan por el caracter de código 27, denominado ESC (por Escape). Asimismo, importamos las bibliotecas sys, que contiene herramientas en tiempo de ejecución de Python, y os, que contiene funciones relacionadas con el sistema operativo.

En las líneas 10 y 11 definimos la función que nos indica si estamos funcionando dentro de IDLE.

En las líneas 13 a 33 creamos tres variables con las secuencias de cambio de color y los nombres de los colores. La función dir(objeto) devuelve una lista con las representaciones en forma de cadenas de texto del contenido de objeto. Por cierto, recuerda que en Python TODO son objetos. Asignamos a las listas fore y back las cadenas de cambio de color, extrayéndolas de los objetos Fore y Back que habíamos importado anteriormente. Esto lo hacemos iterando sobre el contenido en forma de texto de estos objetos, eliminando aquellas entradas que comienzan por el caracter barra-baja "_", que corresponden a entradas reservadas del sistema. También eliminamos el código RESET que sirve para anular los cambios del color de texto o de fondo. Usaremos Style.RESET_ALL que anula cualquier cambio.

Como estamos trabajando con representaciones en forma de texto, tenemos que volver a obtener la propiedad original, para lo cual usamos la función eval() y concatenando la cadena "Fore." o "Back." con cada una de las propiedades obtenidas. Por cierto, si quieres obtener la lista de colores, ejecuta el programa en IDLE (o teclea from colorama import Fore,Back) y sin cerrar la ventana de ejecución teclea:

>>> [i for i in dir(Fore) if i[0]!="_"]
['BLACK', 'BLUE', 'CYAN', 'GREEN', 'LIGHTBLACK_EX', 'LIGHTBLUE_EX', 'LIGHTCYAN_EX', 'LIGHTGREEN_EX', 'LIGHTMAGENTA_EX', 'LIGHTRED_EX', 'LIGHTWHITE_EX', 'LIGHTYELLOW_EX', 'MAGENTA', 'RED', 'RESET', 'WHITE', 'YELLOW']
>>> Fore.BLACK
'\x1b[30m'

Los colores de fondo son los mismos. En la segunda sentencia puedes ver claramente la diferencia entre los identificadores de los códigos de cambio de color y los propios códigos.

Continuando con el programa, en la línea 35 comprobamos si estamos en IDLE y en caso afirmativo presentamos un mensaje y terminamos. Si no estamos en IDLE asumimos que la salida es por la consola estándar de Windows, en la línea 38 usamos una orden del propio Windows para borrar la pantalla y escribimos un encabezamiento. El bucle de las líneas 32-48 imprime la línea de encabezamiento con los colores de fondo, hay algo de código extra para que se vea el mensaje cuando el fondo es negro: Usamos en el bucle la función enumerate(iterable), que devuelve una tupla con el número de índice del elemento y el elemento en sí, guardamos en índice en i y el color de fondo en b (de background). De este modo podemos comprobar cuando estamos en el elemento Back.BLACK (que es el primero) para escribir con texto blanco, también el índice nos permite acceder a los nombres de color en la tupla colores, y los escribimos en un campo de 10 caracteres alineados a la izquierda con el formato <10.

El trabajo serio lo realizan los dos bucles anidados de las líneas 50-59. Usamos la misma técnica para escribir al principio de la fila el nombre del color, asegurándonos de que el negro se imprime sobre fondo blanco. En este caso el campo es de 10 caracteres y alineamos a la derecha los nombres. También dejamos un espacio de separación. A continuación para cada color de fondo escribimos en los colores seleccionados una cadena de 10 caracteres de ancho, y cada vuelta volvemos a los colores por omisión con Style.RESET_ALL. Todas las órdenes de impresión se hacen con el argumento end="" para que no se dejen espacios ni se salten líneas. En la línea 51 se salta para cada línea nueva con otro color de texto.

Abre una ventana de la consola o símbolo del sistema, ve al directorio de tus programas PYTHON con la orden:

cd <mi_directorio_de_programas_python>

En la que debes reemplazar el directorio por lo que corresponda, si hay espacios debes envolver entre comillas toda la línea del directorio, pero no el comando cd (De change dir, cambiar directorio). Una vez en el directorio en cuestión, teclea el nombre completo del programa con la extensión .py, si hay espacios envuélvelo entre comillas. Por fín obtendrás lo siguiente:

Ten en cuenta que necesitas ensanchar la ventana a lo ancho para que los 171 caracteres por línea quepan correctamente. Y aquí dejamos de momento los módulos y cerramos esta extensa introducción. En realidad, con lo tratado hasta ahora dispones del bagaje suficiente para programar cualquier cosa. En la siguiente sección empezaremos a ver en detalle distintos aspectos de la programación en general, y a ir ampliando nuestra perpectiva del lenguaje Python.

1.2.6 RESUMEN

Comentarios
# Desde el caracter # hasta el final de la línea
''' Comentario multilínea
Sentencias multilíneas
\ Al final de línea, continúa una línea en la línea siguiente
Salto de línea Tras un elemento de una secuencia, definición multilínea
Conviene partir la línea después de las comas, e indentar todos los elementos a la misma altura
Bloques de código
: La línea que genera el bloque siempre termina por el caracter dos puntos
indentación Los bloques se indentan de cuatro en cuatro espacios
Sentencias condicionales
if expresión: Evalúa la expresión posterior y si el resultado es True ejecuta el bloque
elif expresión: Dentro de un bloque condicional, si las condiciones anteriores if...elif
no se han cumplido, comprueba una nueva expresión y si es cierta ejecuta el bloque subsiguiente
else: Si ninguna de las condiciones anteriores se ha cumplido, se ejecuta el bloque else
Bucles
while expresión:
else:
Mientras la expresión devuelva True ejecuta repetidamente el bloque siguiente
cuando la condición no se cumple ejecuta el bloque else
for variable in iterador:
else:
Para cada elemento de iterador, asigna el valor del elemento a variable
y ejecuta el bloque a continuación
Cuando el bucle ha recorrido todos los elementos se ejecuta el bloque else
continue Sin terminar el bloque salta a la siguiente iteración del bucle
break Termina el bucle. No se ejecuta la cláusula else si la hubiera
Puedes terminar un bucle (y cualquier programa)
mediante la combinación de teclas: <CTRL>+<C>
Operadores
Lógicos not expr
expr1 and expr2
expr1 or expr2
Negación lógica: invierte el valor de certeza de expr
Producto lógico: Si cualquiera de ambas expresiones es falsa devuelve False
Suma lógica: si cualquiera de ambas expresiones es cierta devuelve True
var:=expr Asignación como expresión Devuelve el valor asignado a var, puede utilizarse en expresiones como en las condiciones de bucles y sentencias condicionales
Secuencias de escape
\\ Barra invertida
\" Comillas dobles
\' Comilla simple
\n Nueva línea
\N{name} Caracter unicode de nombre name
\uxxxx Caracter unicode con código xxxx
\ooo Caracter con código octal ooo
\xhh.. Caracter con código hexadecimal hh..
Cadenas con formato
Las cadenas comienzan con f antes de las comillas
Dentro de la cadena unas llaves {} delimitan una expresión
Se escribe el resultado de evaluar la expresión
A continuación de la expresión, dentro de las llaves, especificamos el formato poniendo el caracter dos puntos
Indicamos un caracter de relleno, luego alineación y ancho del campo
Para valores enteros podemos elegir modo binario, octal, decimal o hexadecimal
Para valores flotantes podemos indicar un punto y el número de dígitos a continuación
Listas inteligentes
Podemos generar valores en una lista como si ejecutáramos un bucle
lista=[x for x in iterador if condición]
El resultado es como ejecutar el siguiente código:

lista=[]
for x in iterador:
  if condición:
    lista.append(x)
Funciones incorporadas
input() var=input(prompt) Escribe la cadena prompt y devuelve una cadena introducida por el usuario mediante el teclado
end
Argumento de print()
print(loQueSea,end=cadena) Escribe en pantalla los argumentos loQueSea y termina con cadena en vez de un salto de línea
range() iterador=range(int)
iterador=range(start,end,step)
Devuelve los enteros desde 0 hasta int-1
Devuelve los enteros desde start hasta end-1 con un incremento de step entre valores
reversed() iterador2=reversed(iterador1) Invierte la secuencia de elementos de iterador1
eval() eval(cadena) Interpreta cadena como una línea de órdenes Python y la ejecuta
chr() ch=chr(int) Devuelve el caracter cuyo código es int
ord() int=ord(ch) Devuelve el código del caracter ch
dir() lista=dir(objeto) Devuelve los nombres de las propiedades y métodos de objeto
enumerate() tupla=enumerate(iterador) Para cada elemento de iterador devuelve el índice y el elemento
append() lista.append(valor) Método de la clase lista
Añade valor a la lista lista
isdecimal() cadena.isdecimal() Método de la clase cadena
Devuelve True si todos los caracteres están entre 0-9
Definición de funciones
def función(): Función sin argumentos
def función(arg1,...,arg_n): Función con argumentos determinados
def función(arg1,...,argx=x,argy=y): Función con argumentos por defecto
def función(*arg): Función con argumentos indeterminados
return x Termina la función y devuelve x como valor de retorno
Importar módulos
import módulo Importar módulo
Acceso a los elementos con módulo.elemento
from módulo import * Importar todos los elementos de módulo
Acceso directo a cada elemento
from módulo import elem, ... Importar determinados elememtos de módulo
Acceso directo a los elementos importados
import módulo as alias Importar módulo
Acceso mediante alias.elemento
from módulo import elem as alias, ... Importar elementos de módulo
Acceso mediante alias
Biblioteca estándar
keyword
keyword.kwlist Lista de palabras reservadas
keyword.iskeyword(str) Comprobar si una cadena corresponde
a una palabra reservada
math
math.ceil(f) Redondeo hacia arriba
math.floor(f) Redondeo hacia abajo
math.trunc(f) Truncado de la parte decimal
math.fsum(x,...) Suma de múltiples valores
math.factorial(i) Factorial
math.gcd(i1,i2) Máximo común divisor
math.log(x) Logaritmo natural
math.log2(x) Logaritmo en base 2
math.log10(x) Logaritmo en base 10
matw.pow(x,y) Potencia
math.sqrt(x) Raíz cuadrada
math.radians(g) Conversión de grados a radianes
math.degrees(r) Conversión de radianes a grados
math.sin(a) Función seno
math.cos(a) Función coseno
math.tan(a) Función tangente
math.e Constante matemática e
math.pi Constante matemática π
random
random.random() Devuelve un valor flotante entre 0 y 1
random.uniform(f1,f2) Devuelve un valor flotante entre f1 y f2
random.randrange(int) Devuelve un valor entero entre 0 e int
random.randrange(s,e,i) Devuelve un valor entero entre s y e con un incremento de i
random.choice(seq) Devuelve uno de los valores de seq
random.shuffle(seq) Baraja el contenido de seq
random.sample(seq,k) Devuelve k valores sin repetir de seq
unicodedata
ud.unidata_version Versión de unicode del intérprete Python
ud.name(ch) Nombre del caracter ch
ud.category(ch) Categoría del caracter ch
ud.lookup(nombre) Caracter llamado nombre, o error si no se encuentra
time
time.time() Devuelve los segundos desde epoch
time.localtime() Devuelve el tiempo local en una estructura struct_time
time.gmtime() Devuelve el tiempo UTC en una estructura struct_time
time.asctime(str_time) Convierte una esctructura struct_time en una representación de texto
struct_time Contiene campos para diversos datos del tiempo:
tm_hour, tm_min, tm_sec, tm_wday, tm_mday, tm_mon, tm_year
sys
sys.modules Devuelve los módulos importados
os
os.system(orden) Ejecuta órdenes del sistema operativo
PiP
pip install paquete Instala paquete y sus dependencias
pip install -U paquete Actualiza paquete
pip list Muestra los paquetes instalados
pip list -o Muestra los paquetes desactualizados
colorama
colorama.init() Función para activar el reconocimiento de secuencias de la consola
colorama.Fore Colores de texto
colorama.Back Colores de fondo
colorama.Style Estilos de texto
Comandos de la consola Windows
cls Borra la consola
cd directorio Cambia al directorio indicado
cd.. Cambia al directorio superior
cd\ Cambia al directorio raíz