Introducción a Python#

Este cuaderno usará Python como lenguaje de programación. Esto significa que la mayor parte de lo aprendido en este curso puede ser desarrollado y aplicado en cuadernos. Los cuadernos se dividen en celdas donde se puede poner código y luego correrlo haciendo Mayúscula + Enter.

Aquí intenta ase intentará mostrarles algunos de los tipo de datos más comunes de Python con el fin de comenzar a interiorizarnos tanto con el lenguaje como con los cuadernos de de Jupyter.

Números#

Python cuenta con varios formatos o tipos de datos para representar números.

Enteros#

Cuando una nueva variable numérica se define Python por defecto lo hace como entero. Por ejemplo:

num = 1
type(num)
int

Punto flotante#

En caso de necesitar números con decimales que no pueden ser representados mediante enteros, Python automáticamente los transforma en números punto flotantes, o float:

num = 1.1
type(num)
float

En caso de necesitar que un número entero sea representado como un flotante, se puede resolver agregando un punto detrás de entero, por ejemplo:

num = 1.
type(num)
float

Otra forma de hacerlo, mucho menos común es:

num = float(1)
type(num)
float

Números complejos#

Python tiene soporte nativo para números complejos usando la letra j de la siguiente manera:

num = 1+2j
print('La variable num toma el siguiente valor: ', num)
print('La variable num es del tipo: ', type(num))
La variable num toma el siguiente valor:  (1+2j)
La variable num es del tipo:  <class 'complex'>

Python soporta ciertas operaciones de forma nativa con los números complejos:

a = 1 + 2j
b = 2 + 5.8j
print(' La suma de a + b es: ', a+b)
 La suma de a + b es:  (3+7.8j)
print('El conjugado de a vale: ', a.conjugate())
El conjugado de a vale:  (1-2j)

Fácilmente podemos obtener la parte real e imaginaria

print('La parte real de a es ', a.real, ' y la parte imaginaria es ',
      a.imag)
La parte real de a es  1.0  y la parte imaginaria es  2.0

Notar la diferencia entre el método conjugate y la propiedad real y la propiedad imag. Mientras que conjugate se comporta como una función propia de número complejo y debemos llamarla usando paréntesis, imag y real se comportan como datos o variables del número complejo.

Listas#

Ejemplo de lista, se acumulan con un patron

inputs = [2, 1, 3, 2, 4, 3, 6]
result = []  # Comenzamos con una lista vacía
for i in inputs:  # Iteramos sobre la lista inputs
    if i < 4:  # si se cumple esta condición agregamos a result
        result.append(i**2)

result
[4, 1, 9, 4, 9]

Es común ver en Python incluya una sintaxis algo diferente del for y el if cuando se tiene que ejecutar una sola línea. El siguiente es un ejemplo con ambos cosas.

result = [i**2 for i in inputs if i < 4]
result.append(1)
result
[4, 1, 9, 4, 9, 1]

Diccionarios#

Una vez familiarizado con las listas, vemos los diccionarios, que son otro tipo de contenedores ordenados.

lst = [1, 2, 3]

Podemos recuperar elementos de la lista mediante indexado

lst[1]
2

Un diccionario nos da un contenedor como una lista, pero los índices pueden ser mucho más generales, no solo números, sino cadenas o variables de cualquier tipo, como por ejemplo sympy (y una gran cantidad de otros tipos)

dic = {'a': 100, 2: 45, 100: 45}
print(dic['a'], dic[2])
100 45
print(dic[0])
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[14], line 1
----> 1 print(dic[0])

KeyError: 0

Tuplas#

Finalmente, otro contenedor es la tupla:

x = 1, 2, 3
a, b, c = x
d, e, f = 4, 5, 6
def f(x):
    Ca, Cb, Cc = x
    return Cb


k = f(x)
print(k)
2
li = [1, 2, 3, 4]
type(li)
list

Las tuplas son como listas, pero se crean con comas:

t = 1, 2, 3, 4
type(t)
tuple

En algunos casos, es útil usar paréntesis para agrupar tuplas, pero tenga en cuenta que no son requerimientos en la sintaxis:

t2 = (1, 2, 3, 4)
type(t2)
tuple

Es importante entender que la coma, no los paréntesis forman tuplas:

only_one = (((((((1)))))))
type(only_one)
int
only_one = 1,
type(only_one)
tuple
len(only_one)
1

La única excepción a esta regla es que una tupla vacía se construye con ():

empty = ()
type(empty)
tuple
len(empty)
0

Las diferencias entre las tuplas y las listas son que las tuplas son inmutables (no se pueden cambiar «inplace»)

li.append(1)
li
[1, 2, 3, 4, 1]

Pero si ejecutamos

t.append(1)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[26], line 1
----> 1 t.append(1)

AttributeError: 'tuple' object has no attribute 'append'

Expansión de la tupla#

Una característica muy útil y general del operador de asignación en Python es que las tuplas se expandirán y asignarán en patrones coincidentes:

a, b = 1, 2

Esto es bastante sofisticado y puede manejar estructuras anidadas y expandirse a listas:

[(a, b,), c, d] = [(1, 2), 1, 4]
[f, g, h] = [(1, 2), 1, 4]
f = 1, 2
print(f)
g = f, 3
print(g)
h = f[0], f[1], 3
print(h)
(1, 2)
((1, 2), 3)
(1, 2, 3)

El bucle for en Python#

Como resumen en Python el bucle for lo que hace es recorrer los elementos de objeto del tipo «iterable». Por ejemplo una lista, un diccionario o un array de numpy son iterables.

Para una lista:

lista_variada = [1, 2, 3., "hola"]
for e in lista_variada:
    print(e)
1
2
3.0
hola

Para un diccionario, va a devolver en cada iteración la key es decir:

mi_diccionario = {"el_1": "Primer item", 2: "segundo item", "3": 45*3.2}
for key in mi_diccionario:
    print("La key es de tipo ", type(key), "y es ", key)
    print("El items de tipo ", type(mi_diccionario[key]),
          "y es ", mi_diccionario[key])
La key es de tipo  <class 'str'> y es  el_1
El items de tipo  <class 'str'> y es  Primer item
La key es de tipo  <class 'int'> y es  2
El items de tipo  <class 'str'> y es  segundo item
La key es de tipo  <class 'str'> y es  3
El items de tipo  <class 'float'> y es  144.0

Finalmente para un array de numpy me va a devolver cada elemento del array

import numpy as np

n = np.linspace(1, 1000, 7)
for i in n:
    print("Elemento al cuadrado", i**2)
Elemento al cuadrado 1.0
Elemento al cuadrado 28056.25
Elemento al cuadrado 111556.0
Elemento al cuadrado 250500.25
Elemento al cuadrado 444889.0
Elemento al cuadrado 694722.25
Elemento al cuadrado 1000000.0

Funciones#

Las funciones en Python se definen a partir de la palabra calve def. Pueden tomar argumentos posicionales, y argumentos con nombres y con valores por defecto. El siguiente es un ejemplo.

def cambio_de_escala(x, m=1, h=0):
    y = [i*m+h for i in x]
    return y

El argumento x es un argumento posicional y es obligatorio a la hora de llamar a la función cambio_de_escala. Los otros dos, pueden estar o no presentes a la hora de llamar. Si no están presentes, usan el valor por defecto definido en la función.

x = [1, 2, 3, 4, 5]
x1 = cambio_de_escala(x)
print(x1)
[1, 2, 3, 4, 5]

Podemos ver que asumió que m=0 y h=1. También podríamos llamarla a la función de la siguiente manera:

x2 = cambio_de_escala(x, m=2, h=1)
print(x2)
[3, 5, 7, 9, 11]

O lo que es lo mismo:

x2 = cambio_de_escala(x, h=1, m=2)
print(x2)
[3, 5, 7, 9, 11]

O equivalentemente:

x2 = cambio_de_escala(x, 1, 2)
print(x2)
[3, 4, 5, 6, 7]

Pero si intentamos sin darle valores a x tendremos:

x3 = cambio_de_escala(m=1, h=2)
print(x3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[39], line 1
----> 1 x3 = cambio_de_escala(m=1, h=2)
      2 print(x3)

TypeError: cambio_de_escala() missing 1 required positional argument: 'x'