B: Introducción a Python

Python es un lenguaje de programación interpretado multipropósito que se está imponiendo como estándar para el análisis de datos.

Lenguaje de programación: Lenguaje artificial que se utiliza para programar (darle órdenes) a un ordenador sobre las acciones que tiene que realizar.

Interpretado: Un lenguaje interpretado utiliza un programa de ordenador (intérprete) que va leyendo línea a línea el programa de ordenador y traduciéndolo «sobre la marcha» a las instrucciones que utiliza el procesador para funcionar.

Multipropósito: Lenguaje que no está específicamente diseñado para un tipo de tareas. En principio se puede usar Python para programar «cualquier cosa».

En este curso la mayoría de los ejemplos se desarrollan utilizando los notebooks de Jupyter. Estos consisten en una página similar a una página web donde se pueden introducir pequeños scripts de Python directamente y que un interprete que integra un servidor web los puede ejecutar en línea. De hecho esto que ahora mismo estás leyendo es uno de esos notebooks (aunque puede que lo estés viendo como la versión «página web», es decir, sin la posibilidad de ejecutar los scripts directamente, sino con los resultados directamente mostrados. Si aún no has instalado Python ni Jupyter, consulta la página de instalación.

A continuacion ponemos algún enlace que puede venirte bien para ahondar en algunos de los conceptos que veremos:

  • Aprende Python: Un curso de Python en general. Muy completito y en español

A continuación haremos una muy breve introducción a Python mediante ejemplos sencillos.

¡Hola Mundo!

Cuando se enseña programación es típico comenzar con el ejemplo «mínimo» que se podría programar. Típicamente dicho programa lo único que hace es imprimir un texto: ¡Hola mundo!. Para ejecutar el siguiente código sitúate en la celda correspondiente y pulsa la tecla Play ▶ de la barra superior. Otra opción es pulsar Ctrl + INTRO estándo en una de las celdas.

[1]:
print("¡Hola Mundo!")
¡Hola Mundo!

Este ejemplo minúsculo ya nos ofrece algo de información sobre este lenguaje de programación: existe una función (una rutina) que se llama print y que lo que hace es imprimir lo que le pasemos como parámetro (lo que aparece entre paréntesis. Además, como en este caso lo que queremos es imprimir una cadena de caracteres los debemos poner entre comillas dobles o simples. "¡Hola Mundo!" o '¡Hola Mundo!'.

Los programas de ordenador normalmente se compondrán de múltiples instrucciones sencillas. Por ejemplo, podemos hacer que nuestro programa imprima más cosas:

[2]:
print("Esto es un ejemplo en el que voy a imprimir varias líneas.")
print("Por ahora todo debe resultar trivial.")

print("Ya que solo es imprimir mensajitos.")
Esto es un ejemplo en el que voy a imprimir varias líneas.
Por ahora todo debe resultar trivial.
Ya que solo es imprimir mensajitos.

Como habrás apreciado cada instrucción print ha imprimido la línea que le habíamos escrito. Pese a que entre el segundo print y el tercero hemos dejado una línea en blanco en nuestro programa, eso no tiene efecto en la salida del mismo.

Variables

Las variables son los «almacenes de información» que tenemos disponibles en nuestro programa. A fin de cuentas un programa de ordenador en esencia lo único que hace es transformar información. Las variables en un programa Python pueden llamarse de cualquier manera (usando letras mayúsculas y minúsculas, números y el símbolo _, siempre y cuando no empiecen por un número). Hay que tener en cuenta que los nombres de variables son sensibles a las mayúsculas y minúsculas. Es decir variable, Variable, VARIABLE y VaRiABlE son 4 varaibles distintas (cada una contendrá su propia información). Por ejemplo:

[3]:
nombre = "John McClane"
nomBre = "Luke Skywalker"

print(nombre)
print(nomBre)
John McClane
Luke Skywalker

En este código hemos asignado el valor "John McClane" a una variable que hemos llamado nombre. Para ello hemos utilizado el operador de asignación = para asignar a una variable un valor concreto. Cuando en la instrucción print le pasamos como parámetro una variable lo que hará será imprimir el valor de dicha variable. ¿Qué pasaría si hubieramos ejecutado lo siguiente?

[4]:
print("nombre")
nombre

Las variables pueden guardar en su interior información de una naturaleza variada: + números enteros (-7, 0, 1), + en coma flotante (-123.456, 32.00), + cadenas de caracteres ("John McClane") (30 funciones interesantes sobre cadenas), + booleanos (verdadero [True] o falso [False]), + y otros tipos más complejos que veremos más adelante.

[5]:
precio = 100.5
unidades = 5

precio_total = precio * unidades

print(precio_total)
502.5

Nota interesante: En Python no se «debe» hablar de variables tal y como se entienden en otros lenguajes. Sin embargo comunmente se habla de variables y podemos entendernos bien con ese concepto. Sin embargo hay diferencias que pueden ser sutiles y la gente con conocimientos en otros lenguajes de programación (especialmente los que estén acostumbrados a lenguajes orientados a objetos o a trabajar con «punteros»). Puedes leer más al respecto.

Nota interesante 2 sobre tipos y tipado en Python: Tipado dinámico y tipado fuerte es un pequeño artículo que versa sobre el tipado en Python y la herramienta de anotaciones que permite obtener algunas de las ventajas del chequeo estático de tipos (en tiempo de compilación) con herramientas adicionales. También en el artículo Anotaciones en funciones hablan un poco más del tema.

Expresiones y operadores

El ejemplo anterior asigna dos valores (uno en coma flotante y el otro un entero) a dos variables y utiliza una expresión para asignar el resultado de multiplicar ambos valores en la variable precio_total. Las expresiones nos permiten hacer cálculos, llamar a otras funciones o evaluar condiciones lógicas. Algunos operadores básicos para componer expresiones:

  • Operadores aritméticos:

    • Suma: +

    • Resta: -

    • Multiplicación: *

    • División: /

    • División entera: //

    • Módulo (resto de la divisón entera): %

    • Exponenciación: **

[6]:
print(37 + 45)
82
[7]:
print(37 - 45)
-8
[8]:
print(5 * 7)
35
[9]:
print(23 / 5)
4.6
[10]:
print(23 // 5)
4
[11]:
print(23 % 5)
3
[12]:
print(3 ** 4)
81

Ejercicio B.1:

Calculemos el valor del polinomio \(f(x) = a x^2 + bx + c\) (con valores \(a\), \(b\) y \(c\)) en un punto \(x\) a su elección.

[13]:
#a =
#b =
#c =
#x =

#resultado =

#print(resultado)

  • Operadores de comparación:

    • Igualdad: ==

    • Desigualdad: !=

    • Mayor: >

    • Menor: <

    • Mayor o igual: >=

    • Menor o igual: <=

[14]:
print(3 == 4)
False
[15]:
print(3 + 1 == 4)
True
[16]:
print(3 != 4)
True
[17]:
print(3 > 4)
False
  • Operadores lógicos:

    • «o» («esto o aquello»): or

    • «y» («esto y aquello»): and

    • Negación («no esto»): not

[18]:
print(3 > 4 or 5 == 5)
True
[19]:
print(3 > 4 and 5 == 5)
False
[20]:
print(not(3 > 4))
True
  • Operadores sobre cadenas:

    • Concatenación: +

    • Repetición: *

[21]:
print("Hola " + "mundo")
print("Hola " * 5)
Hola mundo
Hola Hola Hola Hola Hola

Hagamos un pequeño ejemplo más «complicado». Supongamos que una foto astronómica tiene 4517 segundos de exposición. ¿Cuantas horas, minutos y segundos son?

[22]:
seg_total = 7517
minutos = seg_total // 60
resto_seg = seg_total % 60
hor = minutos // 60
resto_min = minutos % 60

print(f"{seg_total} segundos son {hor} horas, {resto_min} minutos y {resto_seg} segundos")
7517 segundos son 2 horas, 5 minutos y 17 segundos

En el ejemplo anterior hemos usado algunos operadores aritméticos así como una nueva manera de imprimir información, insertando variables en medio de una cadena. Para eso se utiliza una «cadena-f» (f-string Literal String Interpolation) donde podemos incluir expresiones dentro de una cadena de caracteres.


Ejercicio B.2:

Convierta una ascensión recta \(ar = 23.572\) a grados \(^{\circ}\), minutos \('\) y segundos \(''\).

[23]:
#ar = 23.572
#grados =
#minutos =
#segundos =

#print( )

Sentencias condicionales (if … else …)

Hasta ahora nuestros scripts están siendo muy «lineales», con una ristra de instrucciones que se ejecutan de manera secuencial. Sin embargo en ocasiones querremos que el código que dependiendo de una condición se ejecute un código u otro. Para eso se utiliza la sentencia condicional if, cuya sintaxis básica es:

if condicion:
    bloque de código

donde:

  • if es una palabra reservada para este tipo de sentencias

  • condicion es una expresión (típicamente lógica, que devuelva True o False)

  • : delimita el comienzo del bloque de código condicional

  • bloque de codigo son las sentencias que tienen que ejecutarse si se cumple la condicion. Es muy importante que te des cuenta que el bloque de codigo está indentado a la derecha (por ejemplo con un tabulador). Esta es la manera que tiene Python para saber cuales son las sentencias que deben ejecutarse si se cumple la condición o cuales pertenecen a la rama «principal» de ejecución. Un ejemplo:

[24]:
num = 37

# Para comprobar si un número es par obtenemos el resto de dividir por 2 y comprobamos si es 0.
if num % 2 == 0:
    print(f"El número {num} es par")
    print("++++")

if num % 2 == 1:
    print(f"El número {num} es impar")
    print("----")

print("Esto se imprime siempre")
El número 37 es impar
----
Esto se imprime siempre

En el ejemplo hemos incorporado un nuevo elemento. Los «comentarios» en el código. En Python, todo lo que venga a continuación del símbolo # se considera un comentario por lo que podemos incluir anotaciones para nuestro futuro yo que revise el código escrito. Para comentarios multilínea podemos utilizar las comillas triples: """ ... """

La sentencia condicional tiene la posibilidad de indicar un bloque de código adicional para los casos en los que no se cumple la condición:

[25]:
num = 37

"""
Para comprobar si un número es par obtenemos el resto
de dividir por 2 y comprobamos si es 0.
"""
if num % 2 == 0:
    print(f"El número {num} es par")
    print("++++")
else:   # Si no se cumple la condición anterior
    print(f"El número {num} es impar")
    print("----")

print("Esto se imprime siempre")
El número 37 es impar
----
Esto se imprime siempre

Incluso podemos añadir múltiples condiciones para que se vayan comprobando si las anteriores condiciones no se cumplen:

[26]:
num = 37

if num < 0:
    print("El número es negativo")
elif num > 0:
    print("El número es positivo")
else:
    print("El número es 0")
El número es positivo

Por «complicar» un poco la cosa, el código anterior sería equivalente a «anidar» varias sentencias if (porque los bloques condicionales pueden tener más condiciones en su interior:

[27]:
num = 37

if num < 0:
    print("El número es negativo")
else:
    if num > 0:
        print("El número es positivo")
    else:
        print("El número es 0")
El número es positivo

Ejercicio B.3:

Hagamos un bloque de código que identifique un grupo de edad para una edad expresada en años según las siguientes tabla:

  • Menor de 2 años: Bebé

  • Entre 2 y 11 años: Niño

  • Entre 11 y 18 años: Adolescente

  • Entre 18 y 40 años: Adulto joven

  • Entre 40 y 60 años: Adulto que se cree joven

  • Entre 60 y 100 años: Viejuno

  • Más de 100 años: ¿Qué come esta persona?

[28]:
edad = 42  # Cambiar a distintos valores para comprobar nuestro código

# Escribe aquí tu código

Más tipos de datos

Números complejos

En Python existe de manera nativa el tipo número complejo. Para más detalles podemos consultar Números complejos con Python. Algunos ejemplos:

[29]:
c1 = 3 + -5j
c2 = complex(-2, 7)    # Manera alternativa de definirlos

print(f"Suma: {c1 + c2}")
print(f"Multiplicación: {c1 * c2}")
print(f"División: {c1 + c2}")
print(f"Conjugado: {c1.conjugate()}")
print(f"Valor absoluto: {abs(c1)}")
print(f"Parte real: {c1.real}")
print(f"Parte imaginaria: {c1.imag}")
Suma: (1+2j)
Multiplicación: (29+31j)
División: (1+2j)
Conjugado: (3+5j)
Valor absoluto: 5.830951894845301
Parte real: 3.0
Parte imaginaria: -5.0

Listas (y tuplas)

Las colecciones son un tipo de dato compuesto que agrupa varios valores. Las listas son un tipo de colección. Se emplean los símbolos [ y ] para delimitarlos y poder acceder a los componentes individuales de cada lista. Por ejemplo:

[30]:
mi_lista = [7, 5, "Pera", 6+4j, 1.6180]

print(mi_lista)

print(f"Primer elemento: {mi_lista[0]}")

print(f"Tercer elemento: {mi_lista[2]}")

print(f"Segundo elemento empezando por el final: {mi_lista[-2]}")  # ¡Cuidado que esto despista!

print(f"Longitud de la lista: {len(mi_lista)}")
[7, 5, 'Pera', (6+4j), 1.618]
Primer elemento: 7
Tercer elemento: Pera
Segundo elemento empezando por el final: (6+4j)
Longitud de la lista: 5
[31]:
print(f"Recorte de lista desde el segundo al cuarto elemento: {mi_lista[1:4]}")   # ¡Cuidado que esto tambien despista!

print(f"Recorte desde el principio hasta el tercero: {mi_lista[:4]}")

print(f"Recorte desde el tercero al final: {mi_lista[2:]}")
Recorte de lista desde el segundo al cuarto elemento: [5, 'Pera', (6+4j)]
Recorte desde el principio hasta el tercero: [7, 5, 'Pera', (6+4j)]
Recorte desde el tercero al final: ['Pera', (6+4j), 1.618]
[32]:
# Condicional "si está en la lista"
if "Pera" in mi_lista:
    print("¡La pera si está en la lista!")
¡La pera si está en la lista!
[33]:
# Reemplazar un valor
mi_lista[1] = "Cthulhu"
print(f"Elemento cambiado: {mi_lista[1]}")
Elemento cambiado: Cthulhu
[34]:
# Añadir elementos al final de una lista
mi_lista.append("56.34")
print(mi_lista)
[7, 'Cthulhu', 'Pera', (6+4j), 1.618, '56.34']
[35]:
# Añadir elementos en una posición (insertando en medio)
mi_lista.insert(3, "Orion")
print(mi_lista)
[7, 'Cthulhu', 'Pera', 'Orion', (6+4j), 1.618, '56.34']
[36]:
# Concatenar listas
otra_lista = ["Star", 33.45]
mi_lista = mi_lista + otra_lista
print(f"Lista concatenada: {mi_lista}")
Lista concatenada: [7, 'Cthulhu', 'Pera', 'Orion', (6+4j), 1.618, '56.34', 'Star', 33.45]
[37]:
# Eliminar un elemento
mi_lista.remove("Pera")
print(mi_lista)
[7, 'Cthulhu', 'Orion', (6+4j), 1.618, '56.34', 'Star', 33.45]
[38]:
# Eliminar un elemento que está en una posición
mi_lista.pop(-2)
print(mi_lista)
[7, 'Cthulhu', 'Orion', (6+4j), 1.618, '56.34', 33.45]
[39]:
# Eliminar el último elemento
mi_lista.pop()
print(mi_lista)
[7, 'Cthulhu', 'Orion', (6+4j), 1.618, '56.34']
[40]:
# Vaciar una lista
mi_lista.clear()
print(mi_lista)
[]

Ejercicio B.4:

Para la lista dada más abajo consigue que quede con los Planetas ordenados (por proximidad al Sol) usando sustituciones, cortes, etc.

[41]:
planetas = ["Mercurio", "Venus", "Plutón", "Tierra", "Júpiter", "Saturno",
            "Marte", "Urano", "Neptuno"]

# Inserta aquí las instrucciones necesarias para que al imprimir la lista salga con los Planetas ordenados

print(planetas)
['Mercurio', 'Venus', 'Plutón', 'Tierra', 'Júpiter', 'Saturno', 'Marte', 'Urano', 'Neptuno']

Existe otro tipo de dato básico similar a las listas que son las tuplas. En principio son iguales que las listas pero inmutables, es decir, ni sus elementos ni su tamaño se puede variar. Para crear una tupla lo haremos con (elem1, elem2, ...).

[42]:
tupla = (123.2, "Amstrong", -31+4.15j)

print(tupla)
(123.2, 'Amstrong', (-31+4.15j))

Diccionarios

Los diccionarios son estructuras de datos similares a las listas pero que en vez de estar ordenadas con un índice entero la identificación de los datos se hace mediante una clave (key) consistente en una cadena de caracteres. Dentro de un diccionario no puede haber dos elementos con la misma clave. Además, a los diccionarios no se puede acceder por posición, porque internamente los elementos no se guardan siguiendo un orden particular (al menos no necesariamente).

[43]:
estrella = {
    "nombre": "Sirius",
    "magnitud": -1.46,
    "distancia": 8.6
}

print(estrella)

print(f"Magnitud de {estrella['nombre']}: {estrella['magnitud']}")

# Cambiamos el valor de una clave del diccionario
estrella['nombre'] = "Sirio"
print(estrella)
{'nombre': 'Sirius', 'magnitud': -1.46, 'distancia': 8.6}
Magnitud de Sirius: -1.46
{'nombre': 'Sirio', 'magnitud': -1.46, 'distancia': 8.6}
[44]:
print(f"Claves del diccionario: {estrella.keys()}")

print(f"Valores del diccionario: {estrella.values()}")
Claves del diccionario: dict_keys(['nombre', 'magnitud', 'distancia'])
Valores del diccionario: dict_values(['Sirio', -1.46, 8.6])
[45]:
# Añadimos una nueva pareja clave/valor
estrella['constelacion'] = "Canis Maior"
print(estrella)

# Borramos una pareja clave/valor
estrella.pop("magnitud")
print(estrella)

# Comprobamos si existe una clave
if "magnitud" in estrella:
    print("SI tenemos la magnitud de la estrella")
else:
    print("NO tenemos la magnitud de la estrella")

# Vaciamos un diccionario
estrella.clear()
print(estrella)
{'nombre': 'Sirio', 'magnitud': -1.46, 'distancia': 8.6, 'constelacion': 'Canis Maior'}
{'nombre': 'Sirio', 'distancia': 8.6, 'constelacion': 'Canis Maior'}
NO tenemos la magnitud de la estrella
{}

Por supuesto algo muy interesante es que las colecciones pueden tener como valores otras colecciones:

[46]:
# Una lista bidimensional
lista_de_listas = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

print(lista_de_listas[0][1])
2
[47]:
# Un diccionario con diccionarios, tuplas y listas dentro
meteorologia = {
    "pluviosidad": [("8:00", 2), ("12:00", 5), ("16:00", 0)],
    "descripcion": "Lluvioso, principalmente al medio día",
    "horasSol": {
        "salida": "07:43",
        "puesta": "21:32"
    }
}

print(meteorologia["pluviosidad"][2])
print(meteorologia["horasSol"]["puesta"])
('16:00', 0)
21:32

Ejercicio B.5:

Crear una lista llamada planetas que contenga diccionarios. Cada diccionario debe tener información sobre un planeta (nombre, distancia al Sol (en UAs), y si es terrestre o no. Por ejemplo, planetas[3]['terrestre'] debe dar True y planetas[2]['distanciaSol'] debe dar 1.0.

[48]:
# planetas =

# print(planetas[3]['terrestre'])
#print(planetas[2]['distanciaSol'])


Bucles (iteraciones)

while (mientras)

Existen otras sentencias de control que están destinadas a ejecutar de manera iterativa un bloque de instrucciones. Uno de ellos es while cuya sintaxis es:

while condicion:
    bloque de instrucciones

donde:

  • while es la palabra reservada para este bucle (mientras)

  • condicion es la condición que se debe cumplir (mientras que se cumpla la condicion

  • : ya te lo sabes

  • bloque de instrucciones son las instrucciones que deben repetirse mientras que se cumpla una condición

Veamos un ejemplo:

[49]:
print("¡Aprendamos la tabla de multiplicar!")
numero = input("Dime un número (7 por defecto)") or "7"

numero = int(numero)

n = 0
while n <= 10:
    print(f"{numero} x {n} = {numero*n}")
    n += 1
¡Aprendamos la tabla de multiplicar!
Dime un número (7 por defecto)
7 x 0 = 0
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70

Describamos algunas cosas adicionales de este nuevo código: + La función input() nos permite nos permite obtener un valor que introduzca el usuario por teclado. + La función int() convierte un valor (normalmente una cadena) a un valor de tipo número entero + El operador += es una abreviatura del operador de asignación = y el operador de suma +. n += 1 es totalmente equivalente a num = num + 1 (incrementamos en 1 la variable num.

Nota «interesante»: ¿Qué pasa si eliminamos (o comentamos) la instrucción numero = int(numero)?. No te cortes y haz la prueba

Nota «interesante» 2: ¿Qué pasa si eliminamos (o comentamos) la instrucción n += 1?. Antes de probarlo localiza el botón Stop ■ en la barra superior.

for (para)

El bucle for se utiliza normalmente para iterar un número predeterminado de veces o para recorrer todos los elementos de una colección. Su sintaxis es:

for elemento in coleccion:
    bloque de instrucciones

donde:

  • for es la palabra reservada para este tipo de bucle (para)

  • elemento es una variable temporal (su ámbito de existencia es el bloque de instrucciones que contendrá cada elemento de la coleccion, uno por cada iteración de bucle.

  • in es otra palabra reservada para este tipo de bucle (en)

  • coleccion es una lista, diccionario, tupla… sobre la que se iterará en el bucle

  • bloque de instrucciones son las instrucciones que deben repetirse para cada elemento de la colección.

El bucle lo podemos entender como «para cada elemento en la colección ejecutar estas instrucciones».

[50]:
# Para que este ejemplo funcione hay que haber solucionado el ejercicio B.5

#for planeta in planetas:
#    print(f"+ {planeta['nombre']}")
[51]:
astronomo = {
    "Nombre": "Johannes Kepler",
    "Año Nacimiento": 1571,
    "Año Defunción": 1630,
}

# Iteramos por todas las claves
for clave in astronomo:
    print(f"+ {clave}")
+ Nombre
+ Año Nacimiento
+ Año Defunción
[52]:
# Iteramos por todos los valores
for clave in astronomo:
    print(f"+ {astronomo[clave]}")
+ Johannes Kepler
+ 1571
+ 1630
[53]:
# Versión alternativa de iteración por todos los valores
for valor in astronomo.values():
    print(f"+ {valor}")
+ Johannes Kepler
+ 1571
+ 1630
[54]:
# Iteramos por sendas (clave,valor)
for clave, valor in astronomo.items():
    print(f"+ {clave} - {valor}")
+ Nombre - Johannes Kepler
+ Año Nacimiento - 1571
+ Año Defunción - 1630

Ejercicio B.6:

Dada una distancia en UAs imprimir el nombre del planeta cuya órbita está más cerca. Necesitamos el ejercicio B.5 resuelto.

[55]:
distancia = 3.76


# Tu código aquí


# print(planetaMasCercano['nombre'])