¡Hola! Si estás aprendiendo Python, este artículo es para ti. Encontrarás una descripción detallada de la sintaxis de Python y muchos ejemplos de código para guiarte en tu viaje por el mundo de la programación.

Aprenderás Sobre:

¡Comencemos! ✨

💡 Dato: en el artículo usaré estos símbolos <> para indicar que esa parte del código debe ser reemplazado por el elemento descrito en el texto. Por ejemplo, <var> significa que ese elemento sería reemplazado por una variable cuando escribimos el código en Python.

🔹 Variables en Python

El componente principal de cualquier lenguaje de programación es el concepto de una variable. Una variable es un nombre que asignamos y un espacio de memoria que reservamos para un valor en nuestro programa.

En Python, usamos la siguiente sintaxis para crear una variable y para asignarle un valor a esa variable:

<nombre_de_la_variable> = <valor>

Por ejemplo:

edad = 56
nombre = "Nora"
color = "Blue"
notas = [67, 100, 87, 56]

Si el nombre de una variable tiene más de una palabra, la Guía de Estilo para Código Python recomienda separar las palabras con un guion bajo "como se considere necesario para facilitar la lectura del código".

Por ejemplo:

mi_lista = [1, 2, 3, 4, 5]

💡 Tip: La Guía de Estilo para Código Python (PEP 8) tiene muy buenas sugerencias para ayudarte a escribir código limpio y fácil de entender en Python.

🔸 Programa ¡hola, mundo! en Python

Antes de comenzar a ver los tipos de datos y las estructuras de datos que podemos usar en Python, veamos cómo puedes escribir tu primer programa en Python.

Solo debes llamar a la función print() y escribir este mensaje "¡Hola, Mundo!" entre paréntesis:

print("¡Hola, Mundo!")

Al ejecutar el programa, verás este mensaje:

"¡Hola, Mundo!"

💡 Dato: Escribir un programa "¡Hola, Mundo!" es una tradición en la comunidad de desarrolladores a nivel mundial. La mayoría de los desarrolladores comienzan a aprender programación creando este programa.

Genial. Acabas de escribir tu primer programa. Ahora comencemos a ver los tipos de datos y las estructuras de datos integrados que puedes usar en Python.

🔹 Tipos de datos y estructuras de datos integrados en Python

En Python tenemos varios tipos de datos básicos y estructuras de datos integrados con los que podemos trabajar. Cada uno tiene sus aplicaciones específicas. Veámoslos en detalle:

Tipos de datos numéricos en Python: números enteros, números decimales y números complejos

Estos son los tipos de datos numéricos que puedes usar en Python:

Enteros

Los enteros son números que no poseen decimales. Puedes comprobar si un número es un entero con la función type(). Si el resultado es <class 'int'>, entonces el número es un entero.

Por ejemplo:

>>> type(1)
<class 'int'>

>>> type(15)
<class 'int'>

>>> type(0)
<class 'int'>

>>> type(-46)
<class 'int'>

Floats

Los floats son números decimales. Puedes detectarlos visualmente ubicando el punto decimal. Si llamamos a la función type() para comprobar el tipo de dato de estos valores, veremos el siguiente resultado:

<class 'float'>

Aquí tenemos algunos ejemplos:

>>> type(4.5)
<class 'float'>

>>> type(5.8)
<class 'float'>

>>> type(2342423424.3)
<class 'float'>

>>> type(4.0)
<class 'float'>

>>> type(0.0)
<class 'float'>

>>> type(-23.5)
<class 'float'>

Números complejos

Los números complejos tienen una parte real y una parte imaginaria denotada con una j. Puedes crear números complejos en Python con complex(). El primer argumento será la parte real y el segundo argumento será la parte imaginaria.

Estos son algunos ejemplos:

>>> complex(4, 5)
(4+5j)

>>> complex(6, 8)
(6+8j)

>>> complex(3.4, 3.4)
(3.4+3.4j)

>>> complex(0, 0)
0j

>>> complex(5)
(5+0j)

>>> complex(0, 4)
4j

Cadenas de caracteres in Python

Las cadenas de caracteres son muy útiles en Python. Ellas están formadas por una secuencia de caracteres y se usan para representar texto en el código.

Por ejemplo:

"¡Hola, Mundo!"
'¡Hola, Mundo!'

Podemos usar comillas simples o comillas dobles para definir una cadena de caracteres en nuestro programa. Ambas son válidas y equivalentes, pero se recomienda escoger una de ellas y usarla consistentemente en todo el programa.

💡 Dato: ¡Sí! Probablemente acabas de notar que usamos una cadena de caracteres cuando escribimos el programa ¡Hola, Mundo!, así que cuando veas un valor rodeado por comillas simples o dobles en Python, es una cadena de caracteres.

Las cadenas de caracteres pueden contener cualquier carácter que podamos ingresar en nuestro dispositivo incluyendo números, símbolos y caracteres especiales.

Por ejemplo:

"45678"
"mi-correo@email.com"
"#MeEncantaPython"

💡 Datos: Los espacios también representan caracteres en las cadenas de caracteres.

Comillas dentro de cadenas de caracteres

Si definimos una cadena de caracteres con comillas dobles "", entonces podemos usar comillas simples dentro de la cadena de caracteres.

Por ejemplo:

"Mi libro favorito es 'Sense and Sensibility'"

Pero si definimos la cadena de caracteres con comillas simples '', entonces podemos usar comillas dobles dentro de la cadena de caracteres.

Por ejemplo:

'Mi libro favorito es "Sense and Sensibility"'

Indexación de cadenas de caracteres

Podemos usar índices para acceder a los caracteres de una cadena de caracteres en nuestro programa. Un índice es un número entero que representa una posición específica en la cadena de caracteres. Cada índice está asociado al carácter ubicado en esa posición.

Por ejemplo, este es un diagrama de la cadena de caracteres "Hola":

Cadena:    H o l a 
Índices:   0 1 2 3

💡 Dato: los índices inician desde 0 y su valor se incrementa de uno en uno para cada carácter de la cadena de izquierda a derecha.

Por ejemplo:

>>> mi_cadena = "Hola"

>>> mi_cadena[0]
'H'

>>> mi_cadena[1]
'o'

>>> mi_cadena[2]
'l'

>>> mi_cadena[3]
'a'

También podemos usar índices negativos para acceder a estos caracteres de derecha a izquierda:

>>> mi_cadena = "Hola"

>>> mi_cadena[-1]
'a'

>>> mi_cadena[-2]
'l'

>>> mi_cadena[-3]
'o'

>>> mi_cadena[-4]
'H'

💡 Dato: comúnmente usamos el índice -1 para acceder al último carácter de una cadena de caracteres.

Rebanado de cadenas de caracteres

En Python podemos obtener una rebana de una cadena de caracteres (un subconjunto de sus caracteres) de esta forma:

<variable_con_cadena>[inicio:fin:paso]
  • inicio es el índice del primer carácter que será incluido en la rebanada. Por defecto, su valor es 0, así que la rebanada iniciaría desde el primer carácter de la cadena.
  • fin es el índice del último carácter en la rebanada (este carácter no será incluido). Por defecto, es el último carácter de la cadena (si omitimos este valor, el último carácter también será incluido).
  • paso representa cuánto se le sumará al índice actual para alcanzar el índice del próximo carácter de la rebanada. Básicamente determina si se van a "saltar" caracteres antes de incluir el próximo carácter.

Para usar el valor por defecto de paso (1) debemos especificar solo dos valores (argumentos). Esto incluirá todos los caracteres entre los índices de inicio y fin (sin incluir este último carácter):

<variable_con_cadena>[inicio:fin]

Por ejemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[2:8]
'eeCode'

>>> freecodecamp[0:3]
'fre'

>>> freecodecamp[0:4]
'free'

>>> freecodecamp[4:7]
'Cod'

>>> freecodecamp[4:8]
'Code'

>>> freecodecamp[8:11]
'Cam'

>>> freecodecamp[8:12]
'Camp'

>>> freecodecamp[8:13]
'Camp'

💡 Dato: Nota que la rebanada será presentada incluso si el valor de un parámetro está fuera del rango válido de índices. Así es como los creadores de Python implementaron este aspecto del rebanado de cadenas de caracteres.

Si personalizamos el valor del parámetro paso, "saltaremos" de un índice al siguiente de acuerdo a este valor.

Por ejemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[0:9:2]
'feCdC'

>>> freecodecamp[2:10:3]
'eoC'

>>> freecodecamp[1:12:4]
'roa'

>>> freecodecamp[4:8:2]
'Cd'

>>> freecodecamp[3:9:2]
'eoe'

>>> freecodecamp[1:10:5]
'rd'

También podemos usar un paso negativo para crear la rebanada de derecha a izquierda:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp[10:2:-1]
'maCedoCe'

>>> freecodecamp[11:4:-2]
'paeo'

>>> freecodecamp[5:2:-4]
'o'

Y podemos omitir un parámetro para usar su valor por defecto. Solo debemos incluir dos puntos (:) si omitimos inicio, fin, o ambos:

>>> freecodecamp = "freeCodeCamp"

# Valores por defecto para inicio y paso
>>> freecodecamp[:8]
'freeCode'

# Valores por defecto para fin y paso
>>> freecodecamp[4:]
'CodeCamp'

# Valor por defecto para inicio
>>> freecodecamp[:8:2]
'feCd'

# Valor por defecto para fin
>>> freecodecamp[4::3]
'Cem'

# Valores por defecto para inicio y fin
>>> freecodecamp[::-2]
'paeoer'

# Valores por defecto para inicio y fin
>>> freecodecamp[::-1]
'pmaCedoCeerf'

💡 Dato: el último ejemplo es una de las formas más comunes de obtener una copia reversada una cadena de caracteres.

f-strings

En Python 3.6 y versiones más recientes, podemos usar un tipo de cadena de caracteres llamada "f-string" que nos ayuda a crear nuestras cadenas de caracteres más fácilmente.

Para crear una f-string, solo agregamos una f antes de las comillas de apertura. Luego, dentro de la cadena de caracteres, rodeamos las variables o expresiones con llaves {}. Esto reemplaza su valor en la cadena cuando ejecutamos el programa.

Por ejemplo:

nombre = "Nora"
lenguaje_favorito = "Python"

print(f"Hola, soy {nombre}. Estoy aprendiendo {lenguaje_favorito}.")

El resultado es:

Hola, soy Nora. Estoy aprendiendo Python.

Aquí tenemos un ejemplo en el cual calculamos el valor de una expresión y reemplazamos el resultado en la cadena de caracteres:

valor = 5

print(f"{valor} multiplicado por 2 es: {valor * 2}")

Los valores son reemplazados en el resultado:

5 multiplicado por 2 es: 10

También podemos llamar a métodos dentro de las llaves y el valor retornado será reemplazado  en la cadena final cuando ejecutemos el programa:

freecodecamp = "FREECODECAMP"

print(f"{freecodecamp.lower()}")

El resultado es:

freecodecamp

Métodos de cadenas de caracteres

Las cadenas de caracteres también tienen métodos, los cuales nos permiten realizar funcionalidad común que ya fue implementada en Python por los creadores del lenguaje, así que podemos usarlos en nuestros programas directamente. Son muy útiles.

Esta es la sintaxis general para llamar a un método en Python:

<variable_con_cadena>.<método>(<argumentos>)

Por ejemplo:

>>> freecodecamp = "freeCodeCamp"

>>> freecodecamp.capitalize()
'Freecodecamp'

>>> freecodecamp.count("C")
2

>>> freecodecamp.find("e")
2

>>> freecodecamp.index("p")
11

>>> freecodecamp.isalnum()
True

>>> freecodecamp.isalpha()
True

>>> freecodecamp.isdecimal()
False

>>> freecodecamp.isdigit()
False

>>> freecodecamp.isidentifier()
True

>>> freecodecamp.islower()
False

>>> freecodecamp.isnumeric()
False

>>> freecodecamp.isprintable()
True

>>> freecodecamp.isspace()
False

>>> freecodecamp.istitle()
False

>>> freecodecamp.isupper()
False

>>> freecodecamp.lower()
'freecodecamp'

>>> freecodecamp.lstrip("f")
'reeCodeCamp'

>>> freecodecamp.rstrip("p")
'freeCodeCam'

>>> freecodecamp.replace("e", "a")
'fraaCodaCamp'

>>> freecodecamp.split("C")
['free', 'ode', 'amp']

>>> freecodecamp.swapcase()
'FREEcODEcAMP'

>>> freecodecamp.title()
'Freecodecamp'

>>> freecodecamp.upper()
'FREECODECAMP'

Para aprender más sobre los métodos, te recomiendo leer este artículo en la documentación oficial de Python.

💡 Dato: todos los métodos de cadenas de caracteres retornan copias de las cadenas. No pueden modificar las cadenas porque ella son inmutables en Python (no se pueden cambiar).

Valores booleanos en Python

Los valores booleanos son True y False en Python. Deben comenzar con una letra mayúscula para ser reconocidos como valores booleanos.

Por ejemplo:

>>> type(True)
<class 'bool'>

>>> type(False)
<class 'bool'>

Si los escribimos en minúscula, obtenemos un error:

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

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

Listas en Python

Ahora que ya vimos los tipos de datos básicos en Python, comencemos a ver las estructuras de datos que ya vienen integradas en el lenguaje. Primero hablaremos sobre las listas.

Para definir una lista usamos corchetes [] y separamos los elementos con una coma.

💡 Dato: es recomendado incluir un espacio luego de cada coma para mejorar la presentación del código.

Aquí tenemos algunos ejemplos de listas:

[1, 2, 3, 4, 5]
["a", "b", "c", "d"]
[3.4, 2.4, 2.6, 3.5]

Las listas pueden contener valores de distintos tipos de datos, así que la siguiente lista también sería válida en Python:

[1, "Emily", 3.4]

Podemos asignar una lista a una variable:

mi_lista = [1, 2, 3, 4, 5]
letras = ["a", "b", "c", "d"]

Listas anidadas

Las listas pueden contener valores de cualquier tipo de dato, incluso otras listas. Estas listas se denominan listas anidadas.

[[1, 2, 3], [4, 5, 6]]

Aquí tenemos otros ejemplos válidos:

[["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
[1, [2, 3, 4], [5, 6, 7], 3.4]

Podemos acceder a las listas internas con su índice correspondiente (sí, estas listas también tienen índices para sus elementos individuales):

>>> mi_lista = [[1, 2, 3], [4, 5, 6]]

>>> mi_lista[0]
[1, 2, 3]

>>> mi_lista[1]
[4, 5, 6]

Las listas anidadas pueden ser usadas para representar, por ejemplo, la estructura de un tablero sencillo en dos dimensiones donde cada número puede representar un elemento específico:

# Tablero:
# 0 = Espacio vacío
# 1 = Moneda
# 2 = Enemigo
# 3 = Meta
tablero = [[0, 0, 1],
           [0, 2, 0],
           [1, 0, 3]]

Tamaño de una lista

Podemos llamar a la función len() para obtener la longitud o tamaño de la lista (el número de elementos que contiene).

Por ejemplo:

>>> mi_lista = [1, 2, 3, 4]

>>> len(mi_lista)
4

Actualizar un Elemento en una Lista

Podemos actualizar el elemento ubicado en un índice en particular con esta sintaxis:

<variable_lista>[<índice>] = <valor>

Por ejemplo:

>>> letras = ["a", "b", "c", "d"]

>>> letras[0] = "z"

>>> letras
['z', 'b', 'c', 'd']

Agregar un elemento a una lista

Podemos agregar un elemento al final de una lista con el método .append().

Por ejemplo:

>>> mi_lista = [1, 2, 3, 4]

>>> mi_lista.append(5)

>>> mi_lista
[1, 2, 3, 4, 5]

Remover un elemento de una lista

Podemos remover un elemento de una lista con el método .remove().

Por ejemplo:

>>> mi_lista = [1, 2, 3, 4]

>>> mi_lista.remove(3)

>>> mi_lista
[1, 2, 4]

💡 Dato: esto solo removerá la primera ocurrencia del elemento. Por ejemplo, si intentamos remover el número 3 de una lista que contiene dos números 3, el segundo número no será removido.

>>> mi_lista = [1, 2, 3, 3, 4]

>>> mi_lista.remove(3)

>>> mi_lista
[1, 2, 3, 4]

Indexación de listas

Podemos indexar listas al igual que podíamos indexar cadenas de caracteres, con índices que inician desde 0:

>>> letras = ["a", "b", "c", "d"]

>>> letras[0]
'a'

>>> letras[1]
'b'

>>> letras[2]
'c'

>>> letras[3]
'd'

Rebanado de listas

También podemos obtener una rebanada de una lista con la misma sintaxis que usamos con las cadenas de caracteres y podemos omitir parámetros para usar sus valores asignados por defecto.

Ahora, en lugar de añadir caracteres a la rebanada como hacíamos con las cadenas de caracteres, estaremos incluyendo elementos de la lista.

<variable_lista>[inicio:fin:paso]

Por ejemplo:

>>> mi_lista = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]

>>> mi_lista[2:6:2]
['c', 'e']

>>> mi_lista[2:8]
['c', 'd', 'e', 'f', 'g', 'h']

>>> mi_lista[1:10]
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

>>> mi_lista[4:8:2]
['e', 'g']

>>> mi_lista[::-1]
['i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

>>> mi_lista[::-2]
['i', 'g', 'e', 'c', 'a']

>>> mi_lista[8:1:-1]
['i', 'h', 'g', 'f', 'e', 'd', 'c']

Métodos de listas

Python también tiene métodos de listas ya implementados para ayudarnos a realizar operaciones comunes. Estos son algunos ejemplos:

>>> mi_lista = [1, 2, 3, 3, 4]

>>> mi_lista.append(5)
>>> mi_lista
[1, 2, 3, 3, 4, 5]

>>> mi_lista.extend([6, 7, 8])
>>> mi_lista
[1, 2, 3, 3, 4, 5, 6, 7, 8]

>>> mi_lista.insert(2, 15)
>>> mi_lista
[1, 2, 15, 3, 3, 4, 5, 6, 7, 8, 2, 2]

>>> mi_lista.remove(2)
>>> mi_lista
[1, 15, 3, 3, 4, 5, 6, 7, 8, 2, 2]

>>> mi_lista.pop()
2

>>> mi_lista.index(6)
6

>>> mi_lista.count(2)
1

>>> mi_lista.sort()
>>> mi_lista
[1, 2, 3, 3, 4, 5, 6, 7, 8, 15]

>>> mi_lista.reverse()
>>> mi_lista
[15, 8, 7, 6, 5, 4, 3, 3, 2, 1]

>>> mi_lista.clear()
>>> mi_lista
[]

Para aprender más sobre los métodos de listas, te recomiendo leer este artículo en la documentación de Python.

Tuplas in Python

Para definir una tupla en Python, usamos paréntesis () y separamos los elementos con una coma. Se recomienda añadir un espacio luego de cada coma para que el código sea más fácil de leer.

(1, 2, 3, 4, 5)
("a", "b", "c", "d")
(3.4, 2.4, 2.6, 3.5)

También podemos asignar las tuplas a variables:

mi_tupla = (1, 2, 3, 4, 5)

Indexación de Tuplas

Podemos acceder a cada elemento de la tupla con su índice correspondiente:

>>> mi_tupla = (1, 2, 3, 4)

>>> mi_tupla[0]
1

>>> mi_tupla[1]
2

>>> mi_tupla[2]
3

>>> mi_tupla[3]
4

También podemos usar índices negativos:

>>> mi_tupla = (1, 2, 3, 4)

>>> mi_tupla[-1]
4

>>> mi_tupla[-2]
3

>>> mi_tupla[-3]
2

>>> mi_tupla[-4]
1

Tamaño de una Tupla

Para obtener el tamaño de una tupla llamamos a la función len() pasando la tupla como argumento:

>>> mi_tupla = (1, 2, 3, 4)

>>> len(mi_tupla)
4

Tuplas anidadas

Las tuplas pueden contener valores de cualquier tipo de dato, incluyendo listas y otras tuplas. Las tuplas que contienen otras tuplas se denominan tuplas anidadas.

([1, 2, 3], (4, 5, 6))

En este ejemplo, tenemos una tupla interna (4, 5, 6) y una lista. Podemos acceder a la tupla anidada con su índice correspondiente.

Por ejemplo:

>>> mi_tupla = ([1, 2, 3], (4, 5, 6))

>>> mi_tupla[0]
[1, 2, 3]

>>> mi_tupla[1]
(4, 5, 6)

Rebanado de tuplas

Podemos rebanar una tupla de la misma forma que rebanábamos listas y cadenas de caracteres. En este caso aplican las mismas reglas.

Esta es la sintaxis general:

<variable_tupla>[inicio:fin:paso]

Por ejemplo:

>>> mi_tupla = (4, 5, 6, 7, 8, 9, 10)

>>> mi_tupla[3:8]
(7, 8, 9, 10)

>>> mi_tupla[2:9:2]
(6, 8, 10)

>>> mi_tupla[:8]
(4, 5, 6, 7, 8, 9, 10)

>>> mi_tupla[:6]
(4, 5, 6, 7, 8, 9)

>>> mi_tupla[:4]
(4, 5, 6, 7)

>>> mi_tupla[3:]
(7, 8, 9, 10)

>>> mi_tupla[2:5:2]
(6, 8)

>>> mi_tupla[::2]
(4, 6, 8, 10)

>>> mi_tupla[::-1]
(10, 9, 8, 7, 6, 5, 4)

>>> mi_tupla[4:1:-1]
(8, 7, 6)

Métodos de tuplas

Las tuplas tienen dos métodos incorporados (built-in) en Python:

>>> mi_tupla = (4, 4, 5, 6, 6, 7, 8, 9, 10)

>>> mi_tupla.count(6)
2

>>> mi_tupla.index(7)
5

💡 Dato: las tuplas son inmutables. No pueden ser modificadas, así que no podemos añadir, actualizar, o remover elementos de la tupla. Si necesitamos hacerlo, debemos crear una copia nueva de la tupla.

Asignación de tupla

En Python tenemos una opción verdaderamente genial llamada asignación de tupla. Con este tipo de asignación podemos asignar valores a varias variables en la misma línea.

Los valores se asignan a sus variables correspondientes en el orden en el que aparecen.

Por ejemplo, en  a, b = 1, 2, el valor 1 se asigna a la variable a y el valor 2 se asigna a la variable b.

Aquí tenemos el ejemplo y podemos comprobar los valores finales:

>>> a, b = 1, 2

>>> a
1

>>> b
2

💡 Dato: la asignación de tuplas se usa comúnmente para intercambiar los valores de dos o más variables en una sola línea.

>>> a = 1

>>> b = 2

# Intercambiar sus valores
>>> a, b = b, a

>>> a
2

>>> b
1

Diccionarios en Python

Ahora comencemos a hablar sobre los diccionarios. Esta estructura de datos integrada (built-in) nos permite guardar pares de valores en los cuales un valor está asociado con el otro.

Para definir un diccionario en Python, usamos llaves {} y separamos los pares clave-valor con una coma. La clase se separa del valor con dos puntos : de esta forma:

{"a": 1, "b": 2, "c"; 3}

También puedes asignar el diccionario a una variable:

mi_diccionario = {"a": 1, "b": 2, "c"; 3}

Las claves del diccionario deben ser de un tipo de dato inmutable. Por ejemplo, pueden ser cadenas de caracteres, números, o tuplas pero no pueden ser listas ya que las listas son mutables (pueden ser cambiadas).

Estos son algunos ejemplos:

  • Cadenas de caracteres: {"Ciudad 1": 456, "Ciudad 2": 577, "Ciudad 3": 678}
  • Números: {1: "Mover a la Izquierda", 2: "Mover a la Derecha", 3: "Mover Hacia Arriba", 4: "Mover Hacia Abajo"}
  • Tuplas: {(0, 0): "Inicio", (2, 4): "Meta"}

Los diccionarios pueden contener valores de cualquier tipo de dato, así que podemos asignar cadenas de caracteres, números, listas, tuplas, conjuntos, e incluso otros diccionarios como valores.

Por ejemplo:

{"id_producto": 4556, "ingredientes": ["tomate", "queso", "champiñones"], "precio": 10.67}
{"id_producto": 4556, "ingredientes": ("tomate", "queso", "champiñones"), "precio": 10.67}
{"id": 567, "nombre": "Emily", "notas": {"Matemáticas": 80, "Biología": 74, "Inglés": 97}}

Tamaño de un diccionario

Para obtener el número de pares clave-valor en un diccionario, podemos llamar a la función len() pasando el diccionario como argumento:

>>> mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> len(mi_diccionario)
4

Obtener un valor de un diccionario

Para obtener un valor almacenado en un diccionario, podemos usar su clave:

<variable_con_diccionario>[<clave>]

Esta expresión será reemplazada por el valor que corresponde a la clave.

Por ejemplo:

mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

print(mi_diccionario["a"])

El resultado es el valor asociado a la clave "a":

1

Actualizar un valor en un diccionario

Para actualizar el valor asociado a una clave que ya existe en el diccionario, usamos la misma sintaxis pero ahora añadimos el operador de asignación y el valor:

<variable_con_diccionario>[<clave>] = <valor>

Por ejemplo:

>>> mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> mi_diccionario["b"] = 6

Ahora el diccionario es:

{'a': 1, 'b': 6, 'c': 3, 'd': 4}

Añade un par clave-valor a un diccionario

Las claves de un diccionario deben ser únicas. Para añadir un par clave-valor, usamos la misma sintaxis que usamos anteriormente para actualizar un valor, pero ahora la clave no debe existir en el diccionario:

<variable_diccionario>[<clave_nueva>] = <valor>

Por ejemplo:

>>> mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> mi_diccionario["e"] = 5

Ahora el diccionario tiene un nuevo par clave-valor:

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Remover un par clave-valor de un diccionario

Para remover un par clave-valor de un diccionario, usamos la sentencia del:

del <variable_diccionario>[<clave>]

Por ejemplo:

>>> mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> del mi_diccionario["c"]

Ahora el diccionario es:

{'a': 1, 'b': 2, 'd': 4}

Métodos de diccionarios

Estos son algunos ejemplos de los métodos de diccionarios comúnmente usados:

>>> mi_diccionario = {"a": 1, "b": 2, "c": 3, "d": 4}

>>> mi_diccionario.get("c")
3

>>> mi_diccionario.items()
dict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4)])

>>> mi_diccionario.keys()
dict_keys(['a', 'b', 'c', 'd'])

>>> mi_diccionario.pop("d")
4

>>> mi_diccionario.popitem()
('c', 3)

>>> mi_diccionario.setdefault("a", 15)
1

>>> mi_diccionario
{'a': 1, 'b': 2}

>>> mi_diccionario.setdefault("f", 25)
25

>>> mi_diccionario
{'a': 1, 'b': 2, 'f': 25}

>>> mi_diccionario.update({"c": 3, "d": 4, "e": 5})

>>> mi_diccionario.values()
dict_values([1, 2, 25, 3, 4, 5])

>>> mi_diccionario.clear()

>>> mi_diccionario
{}

Para aprender más sobre métodos de diccionarios, te recomiendo leer este artículo en la documentación oficial de Python.

🔸 Operadores en Python

Genial. Ahora que sabes cómo trabajar con los tipos de datos básicos en Python y con las estructuras de datos integradas, comencemos a ver los operadores en Python. Los operadores son esenciales para realizar operaciones y para formar expresiones.

Operadores aritméticos en Python

Estos operadores son:

Suma: +

>>> 5 + 6
11

>>> 0 + 6
6

>>> 3.4 + 5.7
9.1

>>> "Hola" + ", " + "Mundo"
'Hola, Mundo'

>>> True + False
1

💡 Dato: los últimos dos ejemplos son interesantes, ¿no? Este operador se comporta de forma distinta dependiendo del tipo de dato de los operandos (valores).

Cuando los operandos son cadenas de caracteres, este operador concatena (une) las cadenas de caracteres y cuando son valores booleanos, realiza una operación en particular.

En Python, True es equivalente a 1 y False es equivalente a 0. Debido a esto, el resultado del último ejemplo es 1 + 0 = 1.

Resta: -

>>> 5 - 6
-1

>>> 10 - 3
7

>>> 5 - 6
-1

>>> 4.5 - 5.6 - 2.3
-3.3999999999999995

>>> 4.5 - 7
-2.5

>>> - 7.8 - 6.2
-14.0

Multiplicación: *

>>> 5 * 6
30

>>> 6 * 7
42

>>> 10 * 100
1000

>>> 4 * 0
0

>>> 3.4 *6.8
23.119999999999997

>>> 4 * (-6)
-24

>>> (-6) * (-8)
48

>>> "Hola" * 4
'HolaHolaHolaHola'

>>> "Hola" * 0
''

>>> "Hola" * -1
''

💡 Dato: puedes "multiplicar" una cadenas de caracteres por un número entero para repetir una cadena de caracteres un número específico de veces.

Exponenciación: **

>>> 6 ** 8
1679616

>>> 5 ** 2
25

>>> 4 ** 0
1

>>> 16 ** (1/2)
4.0

>>> 16 ** (0.5)
4.0

>>> 125 ** (1/3)
4.999999999999999

>>> 4.5 ** 2.3
31.7971929089206

>>> 3 ** (-1)
0.3333333333333333

División: /

>>> 25 / 5
5.0

>>> 3 / 6
0.5

>>> 0 / 5
0.0

>>> 2467 / 4673
0.5279263856195163

>>> 1 / 2
0.5

>>> 4.5 / 3.5
1.2857142857142858

>>> 6 / 7
0.8571428571428571

>>> -3 / -4
0.75

>>> 3 / -4
-0.75

>>> -3 / 4
-0.75

💡 Dato: este operador retorna un número decimal float como resultado, incluso si la parte decimal es .0.

Si intentas dividir por 0, verás un ZeroDivisionError (error de división por cero).

>>> 5 / 0
Traceback (most recent call last):
  File "<pyshell#109>", line 1, in <module>
    5 / 0
ZeroDivisionError: division by zero

División Entera: //

Este operador retorna un número entero si los operandos son números enteros. Si son números decimales (floats), el resultado será un número decimal con .0 como la parte decimal porque la parte decimal es truncada.

>>> 5 // 6
0

>>> 8 // 2
4

>>> -4 // -5
0

>>> -5 // 8
-1

>>> 0 // 5
0

>>> 156773 // 356
440

Módulo: %

>>> 1 % 5
1

>>> 2 % 5
2

>>> 3 % 5
3

>>> 4 % 5
4

>>> 5 % 5
0

>>> 5 % 8
5

>>> 3 % 1
0

>>> 15 % 3
0

>>> 17 % 8
1

>>> 2568 % 4
0

>>> 245 % 15
5

>>> 0 % 6
0

>>> 3.5 % 2.4
1.1

>>> 6.7 % -7.8
-1.0999999999999996

>>> 2.3 % 7.5
2.3

Operadores de comparación

Estos operadores son:

  • Mayor que: >
  • Mayor o igual que: >=
  • Menor que: <
  • Menor o igual que: <=
  • Igual a: ==
  • No igual a: !=

Estos operadores de comparación crean expresiones que evalúan a True o False. Aquí tenemos algunos ejemplos:

>>> 5 > 6
False

>>> 10 > 8
True

>>> 8 > 8
False

>>> 8 >= 5
True

>>> 8 >= 8
True

>>> 5 < 6
True

>>> 10 < 8
False

>>> 8 < 8
False

>>> 8 <= 5
False

>>> 8 <= 8
True

>>> 8 <= 10
True

>>> 56 == 56
True

>>> 56 == 78
False

>>> 34 != 59
True

>>> 67 != 67

También podemos usarlos para comparar cadenas de caracteres en base a su orden alfabético:

>>> "Hello" > "World"
False
>>> "Hello" >= "World"
False
>>> "Hello" < "World"
True
>>> "Hello" <= "World"
True
>>> "Hello" == "World"
False
>>> "Hello" != "World"
True

Comúnmente usamos estos operadores para comparar el valor de dos o más variables:

>>> a = 1
>>> b = 2

>>> a < b
True

>>> a <= b
True

>>> a > b
False

>>> a >= b
False

>>> a == b
False

>>> a != b
True

💡 Dato: es importante notar que el operador de comparación es == mientras que el operador de asignación es =. Su efecto es diferente. == retorna True o False mientras que = asigna el valor a una variable.

Encadenar operadores de comparación

En Python, podemos encadenar los operadores de comparación para realizar más de una comparación de forma más concisa.

Por ejemplo, esta expresión verifica si a es menor que b y si b es menor que c:

a < b < c

Aquí tenemos algunos ejemplos:

>>> a = 1
>>> b = 2
>>> c = 3

>>> a < b < c
True

>>> a > b > c
False

>>> a <= b <= c
True

>>> a >= b >= c
False

>>> a >= b > c
False

>>> a <= b < c
True

Operadores lógicos

En Python tenemos tres operadores lógicos: and, or, y not. Cada uno de estos operadores tiene su propia tabla de verdad y son esenciales para trabajar con condicionales.

El operador and:

>>> True and True
True

>>> True and False
False

>>> False and True
False

>>> False and False
False

El operador or:

>>> True or True
True

>>> True or False
True

>>> False or True
True

>>> False or False
False

El operador not:

>>> not True
False

>>> not False
True

Estos operadores son usados para formar expresiones más complejas que combinan diferentes operaciones, valores y variables.

Por ejemplo:

>>> a = 6
>>> b = 3

>>> a < 6 or b > 2
True

>>> a >= 3 and b >= 1
True

>>> (a + b) == 9 and b > 1
True

>>> ((a % 3) < 2) and ((a + b) == 3)
False

Operadores de asignación

Estos operadores son usados para asignar un valor a una variable.

Ellos son: =, +=, -=, *=, %=, /=, //=, **=

  • El operador = asigna el valor a una variable.
  • Los otros operadores realizan una operación con el valor actual de la variable y el valor del lado derecho de la sentencia de asignación y asignan el resultado a la misma variable.

Por ejemplo:

>>> x = 3
>>> x
3

>>> x += 15
>>> x
18

>>> x -= 2
>>> x
16

>>> x *= 2
>>> x
32

>>> x %= 5
>>> x
2

>>> x /= 1
>>> x
2.0

>>> x //= 2
>>> x
1.0

>>> x **= 5
>>> x
1.0

💡 Dato: los siguientes operadores realizan operaciones bit a bit antes de asignar el resultado a la variable: &=, |=, ^=, >>=, <<=.

Operadores de membresía

Puedes verificar si un elemento pertenece a una secuencia o no con los operadores in y not in. El resultado será True o False.

Por ejemplo:

>>> 5 in [1, 2, 3, 4, 5]
True

>>> 8 in [1, 2, 3, 4, 5]
False

>>> 5 in (1, 2, 3, 4, 5)
True

>>> 8 in (1, 2, 3, 4, 5)
False

>>> "a" in {"a": 1, "b": 2}
True

>>> "c" in {"a": 1, "b": 2}
False

>>> "h" in "Hola"
False

>>> "H" in "Hola"
True

>>> 5 not in [1, 2, 3, 4, 5]
False

>>> 8 not in (1, 2, 3, 4, 5)
True

>>> "a" not in {"a": 1, "b": 2}
False

>>> "c" not in {"a": 1, "b": 2}
True

>>> "h" not in "Hola"
True

>>> "H" not in "Hola"
False

Los usamos con variables que contienen secuencias, como en este ejemplo:

>>> mensaje = "Hello, World!"

>>> "e" in mensaje
True

🔹 Condicionales en Python

Ahora veamos cómo podemos escribir condicionales para determinar si ciertas partes de nuestro código se deberían ejecutar (o no) en base a si una condición es verdadera o falsa.

Sentencias if en Python

Esta es la sintaxis de una sentencia if básica:

if <condición>:
    <código>
  • Si la condición es verdadera (True), el código del condicional se ejecuta.
  • Si es falsa (False), el código no se ejecuta y se continúa con la ejecución del programa.

💡 Dato: al final de la primera línea debe haber dos puntos (:) y el código que pertenece al condicional debe estar indentado. Esto es esencial en Python.

Aquí tenemos algunos ejemplos:

Condición falsa (False)

x = 5

if x > 9:
    print("¡Hola, Mundo!")

La condición es x > 9 y el código que pertenece al condicional es print("¡Hola, Mundo!").

En este caso, como la condición es False, no se muestra el mensaje.

Condición verdadera (True)

Aquí tenemos otro ejemplo. Ahora la condición es verdadera (True):

color = "Azul"

if color == "Azul":
    print("Este es mi color favorito")

El resultado es:

"Este es mi color favorito"

Código después del condicional

Aquí tenemos un ejemplo con una línea de código que se ejecuta luego de que el condicional se ha completado. Nota que la última línea del código no está indentada, así que no pertenece al condicional.

x = 5

if x > 9:
    print("¡Hola!")

print("Fin")

En este ejemplo, la condición x > 9 es False, así que el código del condicional no se ejecuta pero la última línea sí se ejecuta porque no es parte del condicional, así que el resultado es:

Fin

Sin embargo, si la condición es True, como en este ejemplo:

x = 15

if x > 9:
    print("¡Hola!")

print("Fin")

El resultado es:

¡Hola!
Fin

Ejemplos de condicionales

Este es otro ejemplo de un condicional:

estacion_favorita = "Verano"

if estacion_favorita == "Verano":
    print("¡Esta es mi estación favorita también!")

En este caso, el resultado será:

¡Esta es mi estación favorita también!

Pero si cambiamos el valor de estacion_favorita:

estacion_favorita = "Verano"

if estacion_favorita == "Invierno":
    print("¡Esta es mi estación favorita también!")

No se mostrará el mensaje porque la condición será falsa (False).

Sentencias if/else en Python

Podemos añadir una cláusula else al condicional si necesitamos especificar lo que debería ocurrir cuando la condición es falsa (False).

Esta es la sintaxis general:

if <condición>:
    <código>
else:
    <código>

💡 Dato: nota que ambos bloques de código están indentados (if y else). Esto es esencial para poder diferenciar entre el código que pertenece al programa principal y el código que pertenece al condicional.

Veamos un ejemplo con la cláusula else:

Condición verdadera (True)

x = 15

if x > 9:
    print("¡Hola!")
else:
    print("¡Adiós!")

print("Fin")

El resultado es:

¡Hola!
Fin

Cuando la condición de la cláusula if es verdadera, esta cláusula se ejecuta. La cláusula else no se ejecuta.

Condición falsa (False)

Ahora la cláusula else se ejecuta porque la condición es falsa.

x = 5

if x > 9:
    print("¡Hola!")
else:
    print("¡Adiós!")

print("Fin")

El resultado es:

¡Adiós!
Fin

Sentencias if/elif/else en Python

Para personalizar nuestros condicionales aún más, podemos añadir una o más clausulas elif para verificar y manejar varias condiciones. Solo se ejecuta el código de la primera condición verdadera.

💡 Dato: elif debe estar después de if y antes de else.

Primera condición verdadera (True)

x = 5

if x < 9:
    print("¡Hola!")
elif x < 15:
    print("Me alegra verte")
else:
    print("¡Adiós!")

print("Fin")

Tenemos dos condiciones x < 9 y x < 15. Solo el bloque de código que corresponde a la primera condición verdadera en el orden en el que aparecen será ejecutada.

En este caso, el resultado es:

¡Hola!
Fin

Porque la primera condición es verdadera: x < 9.

Segunda condición Verdadera (True)

Si la primera condición es falsa (False), se verifica la segunda condición.

En este ejemplo, la primera condición x < 9 es falsa (False) pero la segunda condición x < 15 is verdadera (True), así que se ejecutará el código de esta cláusula.

x = 13

if x < 9:
    print("¡Hola!")
elif x < 15:
    print("Me alegra verte")
else:
    print("¡Adiós!")

print("Fin")

El resultado es:

Me alegra verte
Fin

Todas las condiciones Falsas (False)

Si todas las condiciones son falsas, entonces la cláusula else se ejecuta:

x = 25

if x < 9:
    print("¡Hola!")
elif x < 15:
    print("Me alegra verte")
else:
    print("¡Adiós!")

print("Fin")

El resultado es:

¡Adiós!
Fin

Varias cláusulas elif

Podemos agregar tantas cláusulas elif como sea necesario. Este es un ejemplo de un condicional con dos cláusulas elif:

if estacion_favorita == "Invierno":
    print("Esta es mi estación favorita también.")
elif estacion_favorita == "Verano":
    print("Me encanta el verano.")
elif estacion_favorita == "Primavera":
    print("Amo la primavera.")
else:
    print("El otoño es la estación favorita de mi mamá.")

Cada condición será verificada y solo se ejecutará el código que corresponde a la primera condición verdadera. Si ninguna condición es verdadera, se ejecutará la cláusula else.

🔸 Ciclos for en Python

Ahora que ya sabes cómo escribir condicionales en Python, comencemos a hablar sobre los ciclos. Los ciclos for son estructuras asombrosas que podemos usar en nuestro código para repetir un bloque de código un número específico de veces.

Esta es la sintaxis básica para escribir un ciclo for en Python:

for <variable_del_ciclo> in <iterable>:
    <código>

El iterable puede ser una lista, una tupla, un diccionario, una cadena de caracteres, la secuencia retornada por range(), un archivo, o cualquier otro tipo de iterable en Python. Comencemos con range().

La función range() en Python

Esta función retorna una secuencia de enteros que podemos usar para determinar cuántas iteraciones (repeticiones) del ciclo serán ejecutadas. El ciclo completará una iteración por cada número en esta secuencia.

💡 Dato: Cada número entero se asigna a la variable del ciclo uno por uno por cada iteración.

Esta es la sintaxis general para escribir un ciclo for con range():

for <variable_del_ciclo> in range(<inicio>, <fin>, <paso>):
    <código>

Como puedes ver, la función range tiene tres parámetros:

  • inicio: este parámetro determina dónde comienza la secuencia. Por defecto, su valor es 0.
  • fin: este parámetro determina dónde termina la secuencia (sin incluir este valor).
  • paso: este parámetro será sumado a cada número de la secuencia para obtener el próximo elemento. Por defecto, su valor es 1.

Puedes pasar 1, 2, o 3 argumentos a range():

  • Con 1 argumento, el valor se asigna al parámetro fin y se usan los valores por defecto de los otros dos parámetros.
  • Con 2 argumentos, los valores se asignan a los parámetros inicio y fin y se usa el valor por defecto de paso.
  • Con 3 argumentos, los valores se asignan a los parámetros inicio, fin, y paso (en ese orden).

Aquí tenemos algunos ejemplos con un parámetro:

>>> for i in range(5):
        print(i)

Resultado:

0
1
2
3
4

💡 Dato: la variable del ciclo se actualiza automáticamente.

>>> for j in range(15):
        print(j * 2)

Resultado:

0
2
4
6
8
10
12
14
16
18
20
22
24
26
28

En este ejemplo, repetimos una cadena de caracteres tantas veces como indica el valor de la variable del ciclo:

for num in range(8):
    print("Hola" * num)

Resultado:

Hola
HolaHola
HolaHolaHola
HolaHolaHolaHola
HolaHolaHolaHolaHola
HolaHolaHolaHolaHolaHola
HolaHolaHolaHolaHolaHolaHola

También podemos usar ciclos for con estructuras de datos incorporadas (built-in) como listas:

>>> mi_lista = ["a", "b", "c", "d"]

>>> for i in range(len(mi_lista)):
	print(mi_lista[i])

Resultado:

a
b
c
d

💡 Dato: con range(len(<seq>)), obtienes una secuencia de números desde 0 hasta len(<seq>)-1. Esto representa los índices válidos de la secuencia.

Aquí tenemos algunos ejemplos con dos parámetros:

>>> for i in range(2, 10):
	print(i)

Resultado:

2
3
4
5
6
7
8
9

Código:

>>> for j in range(2, 5):
	print("Python" * j)

Resultado:

PythonPython
PythonPythonPython
PythonPythonPythonPython

Código:

>>> mi_lista = ["a", "b", "c", "d"]

>>> for i in range(2, len(mi_lista)):
	print(mi_lista[i])

Resultado:

c
d

Código:

>>> mi_lista = ["a", "b", "c", "d"]

>>> for i in range(2, len(mi_lista)-1):
	mi_lista[i] *= i

Ahora la lista es: ['a', 'b', 'cc', 'd']

Aquí tenemos algunos ejemplos con tres parámetros:

>>> for i in range(3, 16, 2):
	print(i)

Resultado:

3
5
7
9
11
13
15

Código:

>>> for j in range(10, 5, -1):
	print(j)

Resultado:

10
9
8
7
6

Código:

>>> mi_lista = ["a", "b", "c", "d", "e", "f", "g"]

>>> for i in range(len(mi_lista)-1, 2, -1):
	print(mi_lista[i])

Resultado:

g
f
e
d

Cómo Iterar sobre Iterables en Python

Podemos iterar directamente sobre iterables tales como listas, tuplas, diccionarios, cadenas de caracteres y archivos con ciclos for. Obtendremos cada uno de sus elementos uno a la vez en cada iteración.

Esto es muy útil para trabajar con estos elementos directamente. Veamos algunos ejemplos:

Iterar sobre una cadena de caracteres

Si iteramos sobre una cadena de caracteres, sus caracteres serán asignados a la variable del ciclo uno a uno (incluyendo espacios y símbolos):

>>> mensaje = "Hola Mundo"

>>> for char in mensaje:
	print(char)

	
H
o
l
a

M
u
n
d
o

También podemos iterar sobre una copia modificada de la cadena de caracteres llamando a un método de cadenas de caracteres donde normalmente especificamos el nombre del iterable en el ciclo for. Esto asignará la copia de la cadena como el iterable y se usará para las iteraciones.

Aquí tenemos dos ejemplos:

>>> palabra = "Hola"

>>> for char in palabra.lower(): # Llamando al método de cadenas
	print(char)

	
h
o
l
a
>>> palabra = "Hola"

>>> for char in palabra.upper(): # Llamando al método de cadenas
	print(char)

	
H
O
L
A

Iterar sobre listas y tuplas

>>> mi_lista = [2, 3, 4, 5]

>>> for num in mi_lista:
	print(num)

El resultado es:

2
3
4
5

Código:

>>> mi_lista = (2, 3, 4, 5)

>>> for num in mi_lista:
	if num % 2 == 0:
		print("Par")
	else:
		print("Impar")

Resultado:

Par
Impar
Par
Impar

Iterar sobre las claves, los valores y los pares clave-valor de diccionarios

Podemos iterar sobre las claves, los valores, y los pares clave-valor de un diccionario llamando a métodos específicos de diccionarios. Veamos cómo.

Para iterar sobre las claves, escribimos:

for <variable> in <variable_diccionario>:
    <código>

Solo escribimos el nombre de la variable que contiene al diccionario como el iterable.

💡 Dato: también puedes usar <variable_diccionario>.keys() pero escribir el nombre de la variable directamente es más conciso y equivalente.

Por ejemplo:

>>> mi_dicc = {"a": 1, "b": 2, "c": 3}

>>> for clave in mi_dicc:
	print(clave)

	
a
b
c

💡 Dato: puedes asignar cualquier nombre válido a la variable del ciclo.

Para iterar sobre los valores de los pares clave-valor, usamos:

for <variable> in <variable_diccionario>.values():
    <código>

Por ejemplo:

>>> mi_dicc = {"a": 1, "b": 2, "c": 3}

>>> for valor in mi_dicc.values():
	print(valor)

	
1
2
3

Para iterar sobre los pares clave-valor, usamos:

for <clave>, <valor> in <variable_diccionario>.items():
    <código>

💡 Dato: estamos definiendo las dos variables del ciclo porque queremos asignar la clave y el valor a variables del ciclo distintas que podemos usar luego en el cuerpo del ciclo.

>>> mi_dicc = {"a": 1, "b": 2, "c": 3}

>>> for clave, valor in mi_dicc.items():
	print(clave, valor)

	
a 1
b 2
c 3

Si solo definimos una variable del ciclo, esta variable tendrá una tupla con el par clave-valor:

>>> mi_dicc = {"a": 1, "b": 2, "c": 3}

>>> for par in mi_dicc.items():
	print(par)

	
('a', 1)
('b', 2)
('c', 3)

Break y continue en python

Ya sabes cómo iterar sobre secuencias en Python. También tenemos sentencias que nos permiten personalizar qué debe ocurrir cuando se ejecuta el ciclo: break y continue.

La sentencia break

La sentencia break es usada para detener el ciclo inmediatamente.

Cuando se encuentra una sentencia break durante la ejecución del ciclo, el ciclo se detiene y el programa continúa su ejecución normal más allá del ciclo.

En el siguiente ejemplo, detenemos el ciclo si se encuentra un elemento par:

>>> mi_lista = [1, 2, 3, 4, 5]

>>> for elem in mi_lista:
	if elem % 2 == 0:
		print("Par:", elem)
		print("break")
		break
	else:
		print("Impar:", elem)

		
Impar: 1
Par: 2
break

La sentencia continue

La sentencia continue es usada para saltar u omitir lo que falta de la iteración actual.

Cuando se encuentra continue durante la ejecución del ciclo, la iteración actual se detiene y una nueva iteración comienza con el valor actualizado de la variable del ciclo.

En el siguiente ejemplo, saltamos la iteración actual si el elemento es par y solo mostramos el valor si el elemento es impar:

>>> mi_lista = [1, 2, 3, 4, 5]

>>> for elem in mi_lista:
	if elem % 2 == 0:
		print("continue")
		continue
	print("Impar:", elem)

	
Impar: 1
continue
Impar: 3
continue
Impar: 5

La función zip() en Python

zip() es una función incorporada (built-in) en Python (viene con el lenguaje de programación) que podemos usar para iterar sobre varias secuencias de forma simultánea y obtener sus elementos correspondientes en cada iteración.

Solo debemos pasar las secuencias como argumentos a la función zip() y usar este resultado en el ciclo.

Por ejemplo:

>>> mi_lista1 = [1, 2, 3, 4]
>>> mi_lista2 = [5, 6, 7, 8]

>>> for elem1, elem2 in zip(mi_lista1, mi_lista2):
	print(elem1, elem2)

	
1 5
2 6
3 7
4 8

La función enumerate() en Python

También puedes actualizar un contador mientras el ciclo se ejecuta con la función enumerate(). Es comúnmente usada para iterar sobre una secuencia y obtener el índice del elemento correspondiente.

💡 Dato: Por defecto, el contador inicia en 0.

Por ejemplo:

>>> mi_lista = [5, 6, 7, 8]

>>> for i, elem in enumerate(mi_lista):
	print(i, elem)

	
0 5
1 6
2 7
3 8
>>> palabra = "Hola"

>>> for i, char in enumerate(palabra):
	print(i, char)

	
0 H
1 o
2 l
3 a

Si inicias el contador desde 0, puedes usar el índice y el elemento en la misma iteración para modificar la secuencia:

>>> mi_lista = [5, 6, 7, 8]

>>> for indice, num in enumerate(mi_lista):
	mi_lista[indice] = num * 3

>>> mi_lista
[15, 18, 21, 24]

Puedes iniciar el contador desde un número distinto pasando un segundo argumento a enumerate():

>>> palabra = "Hola"

>>> for i, char in enumerate(palabra, 2):
	print(i, char)

	
2 H
3 o
4 l
5 a

La cláusula else

Los ciclos for también tienen una cláusula else. Puedes agregar esta cláusula al ciclo si debes ejecutar un bloque de código específico solo si el ciclo completa todas las iteraciones sin ejecutar una sentencia break.

💡 Dato: si se ejecuta break, la cláusula else no se ejecuta. Si break no se ejecuta, la cláusula else sí se ejecuta.

En el siguiente ejemplo, intentamos encontrar un elemento mayor que 6 en la lista. Ese elemento no se consigue, así que no se ejecuta break y la cláusula else se ejecuta.

mi_lista = [1, 2, 3, 4, 5]

for elem in mi_lista:
    if elem > 6:
        print("Encontrado")
        break
else:
    print("No se Encontró")

El resultado es:

No se Encontró

Sin embargo, si se ejecuta la sentencia break, la cláusula else no se ejecuta. Podemos ver esto en el siguiente ejemplo:

mi_lista = [1, 2, 3, 4, 5, 8] # Ahora la lista tiene el valor 8

for elem in mi_lista:
    if elem > 6:
        print("Encontrado")
        break
else:
    print("No se Encontró")

El resultado es:

Encontrado

🔹 Ciclos while en Python

Los ciclos while son parecido a los ciclos for porque nos permiten repetir un bloque de código. Su diferencia es que los ciclos while continúan su ejecución mientras una condición es verdadera.

En un ciclo while, definimos la condición, no el número de iteraciones. El ciclo se detiene cuando la condición es falsa (False).

Esta es la sintaxis general de un ciclo while:

while <condición>:
    <código>

💡 Dato: en los ciclos while debes actualizar el valor de las variables que son parte de la condición para asegurarte de que la condición en algún momento sea falsa.

Por ejemplo:

>>> x = 6

>>> while x < 15:
	print(x)
	x += 1

	
6
7
8
9
10
11
12
13
14
>>> x = 4

>>> while x >= 0:
	print("Hola" * x)
	x -= 1

	
HolaHolaHolaHola
HolaHolaHola
HolaHola
Hola
>>> num = 5

>>> while num >= 1:
	print("*" * num)
	num -= 2

	
*****
***
*

Break and continue

También podemos usar break y continue con ciclos while. Ambas sentencias funcionan exactamente igual:

  • break detiene inmediatamente el ciclo while.
  • continue detiene la iteración actual e inicia la próxima.

Por ejemplo:

>>> x = 5

>>> while x < 15:
	if x % 2 == 0:
		print("Par:", x)
		break
	print(x)
	x += 1
    

5
Par: 6
>>> x = 5

>>> while x < 15:
	if x % 2 == 0:
		x += 1
		continue
	print("Impar:", x)
	x += 1

	
Impar: 5
Impar: 7
Impar: 9
Impar: 11
Impar: 13

La cláusula else

También podemos agregar una cláusula else al ciclo while.

  • Si se ejecuta break, la cláusula else no se ejecuta.
  • Si la sentencia break no se ejecuta, la cláusula else se ejecuta.

En el siguiente ejemplo, la sentencia break no se ejecuta porque ninguno de los números son pares antes de que la condición del ciclo while sea falsa, así que la cláusula else se ejecuta.

x = 5

while x < 15:
	if x % 2 == 0:
		print("Número Par Encontrado")
		break
	print(x)
	x += 2
else:
	print("Todos los números son impares")

Este es el resultado:

5
7
9
11
13
Todos los números son impares

Pero en esta versión del ejemplo, la sentencia break sí se ejecuta, así que la cláusula else no se ejecuta:

x = 5

while x < 15:
	if x % 2 == 0:
		print("Número Par Encontrado")
		break
	print(x)
	x += 1 # Ahora incrementamos el valor en 1
else:
	print("Todos los números son impares")

El resultado es:

5
Número Par Encontrado

Ciclos while infinitos

Cuando escribimos y ejecutamos ciclos while, podemos obtener algo llamado "ciclo infinito." Si la condición nunca es falsa (False), el ciclo nunca se detendrá sin intervención externa.

Esto normalmente ocurre cuando las variables de la condición no se actualizan correctamente durante la ejecución del ciclo.

💡 Dato: debes hacer los cambios necesarios a los valores de las variables para asegurarte de que la condición en sea falsa en algún momento.

Por ejemplo:

>>> x = 5

>>> while x > 2:
	print(x)

	
5
5
5
5
5
5
5
5
5
.
.
.
# Continúa

💡 Dato: para detener el proceso, puedes usar el atajo de teclado CTRL + C. Verás este error KeyboardInterrupt.

🔸 Ciclos anidados en Python

Puedes escribir ciclos for dentro de ciclos for y ciclos while dentro de ciclos while. Estos ciclos se denominan ciclos anidados.

💡 Dato: el ciclo interno se ejecuta completamente por cada iteración del ciclo externo.

Ciclos anidados en Python

>>> for i in range(3):
	for j in range(2):
		print(i, j)

		
0 0
0 1
1 0
1 1
2 0
2 1

Si añadimos estas llamadas a print, podemos ver lo que está ocurriendo detrás de escenas:

>>> for i in range(3):
	print("===> Ciclo Externo")
	print(f"i = {i}")
	for j in range(2):
		print("Ciclo Interno")
		print(f"j = {j}")

		
===> Ciclo Externo
i = 0
Ciclo Interno
j = 0
Ciclo Interno
j = 1
===> Ciclo Externo
i = 1
Ciclo Interno
j = 0
Ciclo Interno
j = 1
===> Ciclo Externo
i = 2
Ciclo Interno
j = 0
Ciclo Interno
j = 1

El ciclo interno completa dos iteraciones por cada iteración del ciclo externo. Las variables del ciclo se actualizan cuando inicia una nueva iteración.

Este es otro ejemplo:

>>> num_filas = 5

>>> for i in range(5):
	for num_columnas in range(num_filas-i):
		print("*", end="")
	print()

	
*****
****
***
**
*

Ciclos while anidados en Python

Aquí tenemos un ejemplo de ciclos while anidados. En este caso, debemos actualizar las variables que son parte de las condiciones para garantizar que los ciclos terminarán.

>>> i = 5

>>> while i > 0:
        j = 0
        while j < 2:
            print(i, j)
            j += 1
        i -= 1

	
5 0
5 1
4 0
4 1
3 0
3 1
2 0
2 1
1 0
1 1

💡 Dato: también podemos tener ciclos for dentro de ciclos while y ciclos while dentro de ciclos for.

🔹 Funciones en Python

En Python, podemos definir funciones que nos permiten escribir código reutilizable, más fácil de leer y mejor organizado. Esta es la sintaxis básica de una función en Python:

def <nombre_de_la_función>(<parámetro1>, <parámetro2>, ...):
    <código>

💡 Dato: una función puede tener cero, uno, o más parámetros.

Función sin parámetros en Python

Una función sin parámetros tiene un par de paréntesis vacíos después de su nombre en la definición de la función.

Por ejemplo:

def mostrar_patron():
    size = 4
    for i in range(size):
        print("*" * size)

Este es el resultado cuando llamamos a la función:

>>> mostrar_patron()
****
****
****
****

💡 Dato: Para llamar a la función debes escribir un par de paréntesis vacíos luego de su nombre.

Función con un parámetro en Python

Una función con uno o más parámetros tiene una lista de parámetros rodeados por paréntesis luego de su nombre en la definición de la función:

def dar_la_bienvenida(nombre):
    print(f"¡Hola, {nombre}!")

Cuando llamamos a la función, solo debemos pasar un valor como argumento y ese valor será reemplazado donde usamos el parámetro en la definición de la función:

>>> dar_la_bienvenida("Nora")
¡Hola, Nora!

Aquí tenemos otro ejemplo: una función que muestra un patrón con asteriscos. Debes especificar cuántas filas deseas mostrar:

def mostrar_patron(num_filas):
    for i in range(num_filas):
        for num_columnas in range(num_filas-i):
            print("*", end="")
        print()

Puedes ver los resultados para distintos valores de num_filas:

>>> mostrar_patron(3)
***
**
*

>>> mostrar_patron(5)
*****
****
***
**
*

>>> mostrar_patron(8)
********
*******
******
*****
****
***
**
*

Funciones con dos o más parámetros en Python

Para definir dos o más parámetros, solo debemos separarlos con una coma en la lista de parámetros de la definición de la función:

def mostrar_suma(a, b):
    print(a + b)

Ahora, cuando llamamos a la función debemos pasar dos argumentos (valores):

>>> mostrar_suma(4, 5)
9

>>> mostrar_suma(8, 9)
17

>>> mostrar_suma(0, 0)
0

>>> mostrar_suma(3, 5)
8

Podemos adaptar la función anterior con un solo parámetro para que ahora tome dos parámetros y mostrar un patrón con un carácter personalizado en lugar de asteriscos:

def mostrar_patron(num_filas, char):
	for i in range(num_filas):
		for num_cols in range(num_filas-i):
			print(char, end="")
		print()

Puedes ver el resultado con el carácter personalizado que pasamos a la función cuando pasamos ambos argumentos:

>>> mostrar_patron(5, "A")
AAAAA
AAAA
AAA
AA
A

>>> mostrar_patron(8, "%")
%%%%%%%%
%%%%%%%
%%%%%%
%%%%%
%%%%
%%%
%%
%

>>> mostrar_patron(10, "#")
##########
#########
########
#######
######
#####
####
###
##
#

Cómo retornar un valor en Python

Genial. Ya sabes cómo definir una función, así que veamos cómo puedes trabajar con sentencias return.

Muy frecuentemente necesitaremos retornar un valor de una función. Podemos hacerlo con la sentencia return en Python. Solo debemos incluir esta línea en la definición de la función:

return <valor_a_retornar>

💡 Dato: la función se detiene inmediatamente cuando se ejecuta la sentencia return y el valor es retornado.

Aquí tenemos un ejemplo:

def calcular_area_rectangulo(base, altura):
    return base * altura

Ahora podemos llamar a la función y asignar el resultado a una variable:

>>> area = calcular_area_rectangulo(4, 5)
>>> area
20

También podemos usar return en un condicional para retornar un valor en base a si una condición es verdadera o falsa.

En este ejemplo, la función retorna el primer elemento par encontrado en la secuencia:

def retornar_primer_par(secuencia):
    for elem in secuencia:
        if elem % 2 == 0:
            return elem
    else:
        return None

Si llamamos a la función, podemos ver los resultados que esperábamos:

>>> valor1 = retornar_primer_par([2, 3, 4, 5])
>>> valor1
2
>>> valor2 = retornar_primer_par([3, 5, 7, 9])
>>> print(valor2)
None

💡 Dato: si una función no tiene una sentencia return o no se encuentra una durante su ejecución, el valor None es retornado por defecto.

La Guía de Estilo de Python recomienda usar sentencias return consistentemente. Allí se menciona que debemos:

Ser consistentes en las sentencias return. Todas las sentencias return en una función deberían retornar una expresión o, en caso contrario, ningunas de ellas debería retornar una expresión. Si alguna sentencia return retorna una expresión, cualquier sentencia return en la cual no se retorna una expresión debe ser explicita y retornar None. Una sentencia return explícita debería estar presente al final de la función (si se puede alcanzar).

(texto original en inglés)

Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable).

Argumentos por defecto en Python

Podemos asignar argumentos por defecto para los parámetros de nuestra función. Para hacerlo, solo necesitamos escribir <parámetro>=<valor> en la lista de parámetros.

💡 Dato: La Guía de Estilo de Python menciona que no deberíamos "usar espacios alrededor del signo = cuando se usa para indicar un argumento por defecto."

En este ejemplo, asignamos el valor por defecto 5 al parámetro b. Si omitimos este valor cuando llamamos a la función, se usará el valor asignado por defecto:

def mostrar_producto(a, b=5):
    print(a * b)

Si llamamos a la función sin este argumento, puedes ver el resultado:

>>> mostrar_producto(4)
20

Confirmamos que el argumento asignado por defecto 5 fue usado en la operación matemática.

Pero también podemos asignarle un valor personalizado a b pasando un segundo argumento:

>>> mostrar_producto(3, 4)
12

💡 Dato: los parámetros con argumentos por defecto deben estar definidos al final de la lista de parámetros. En caso contrario, verás este error: SyntaxError: non-default argument follows default argument.

Aquí tenemos otro ejemplo con la función que definimos para mostrar un patrón. Asignamos el valor por defecto "*" al parámetro char.

def mostrar_patron(num_filas, char="*"):
	for i in range(num_filas):
		for num_cols in range(num_filas-i):
			print(char, end="")
		print()

Ahora tenemos la opción de usar el valor por defecto o personalizarlo:

>>> mostrar_patron(5)
*****
****
***
**
*

>>> mostrar_patron(6, "&")
&&&&&&
&&&&&
&&&&
&&&
&&
&

🔸 Recursión en Python

Una función recursiva es una función que se llama a sí misma. Estas funciones deben tener un caso base que detiene el proceso recursivo y un caso recursivo que continúa el proceso recursivo al hacer otra llamada recursiva.

Aquí tenemos algunos ejemplos en Python:

def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n-1)
Función Factorial Recursiva.
def fibonacci(n):
    if n == 0 or n == 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)
La Función Fibonacci.
def calcular_potencia(a, b):
    if b == 0:
        return 1
    else:
        return a * calcular_potencia(a, b-1)
Encontrar una Potencia de forma Recursiva.

🔹 Manejo de excepciones en Python

Un error o evento inesperado que ocurre durante la ejecución de un programa se denomina excepción. Gracias a las estructuras que veremos en tan solo un momento, podemos evitar terminar el programa de forma abrupta cuando esto ocurra.

Comencemos viendo los tipos de excepciones en Python y cómo podemos manejarlas.

Excepciones comunes en Python

Esta es una lista de excepciones comunes en Python y por qué ocurren:

  • ZeroDivisionError: esta excepción ocurre cuando el segundo argumento de una operación de división o módulo es cero.
>>> 5 / 0
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    5 / 0
ZeroDivisionError: division by zero

>>> 7 // 0
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    7 // 0
ZeroDivisionError: integer division or modulo by zero

>>> 8 % 0
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    8 % 0
ZeroDivisionError: integer division or modulo by zero
  • IndexError: esta excepción ocurre cuando intentamos usar un índice inválido para acceder a un elemento de una secuencia.
>>> mi_lista = [3, 4, 5, 6]

>>> mi_lista[15]
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    my_list[15]
IndexError: list index out of range
  • KeyError: esta excepción ocurre cuando intentamos acceder a un par clave-valor que no existe porque la clave no está en el diccionario.
>>> mi_diccionario = {"a": 1, "b": 2, "c": 3}

>>> mi_diccionario["d"]
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    my_dict["d"]
KeyError: 'd'
  • NameError: esta excepción ocurre cuando intentamos usar una variable que no ha sido definida previamente en el programa.
>>> b
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    b
NameError: name 'b' is not defined
  • RecursionError: esta excepción ocurre cuando se detecta que la profundidad máxima de recursión se ha alcanzado y aún así se intenta continuar con el proceso recursivo. Esto ocurre cuando el proceso recursivo nunca llega al caso base.

En el siguiente ejemplo ocurre una excepción de tipo RecursionError. La función factorial fue implementada de forma recursiva pero el argumento pasado a la llamada recursiva es n en lugar de n-1. A menos que el valor ya sea 0 o 1, el caso base no se alcanzará nunca porque el argumento no se disminuye, así que el proceso va a continuar y ocurrirá este error:

>>> def factorial(n):
	if n == 0 or n == 1:
		return 1
	else:
		return n * factorial(n)

	
>>> factorial(5)
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    factorial(5)
  File "<pyshell#5>", line 5, in factorial
    return n * factorial(n)
  File "<pyshell#5>", line 5, in factorial
    return n * factorial(n)
  File "<pyshell#5>", line 5, in factorial
    return n * factorial(n)
  [Previous line repeated 1021 more times]
  File "<pyshell#5>", line 2, in factorial
    if n == 0 or n == 1:
RecursionError: maximum recursion depth exceeded in comparison

💡 Dato: Para aprender más sobre estas excepciones, recomiendo leer este artículo de la documentación.

try / except en Python

Podemos usar try/except en Python para detectar las excepciones cuando ocurren y manejarlas apropiadamente. De esta forma, el programa puede terminar adecuadamente e incluso recuperarse de la excepción y continuar con su ejecución.

Esta es la sintaxis básica:

try:
    <código que puede generar una excepción>
except:
    <código que maneja la excepción si ocurre>

Por ejemplo, si tomamos valores ingresados por el usuario para acceder a un elemento de una lista, el valor puede ser un índice inválido, así que puede ocurrir una excepción:

indice = int(input("Ingrese el índice: "))

try:
    mi_lista = [1, 2, 3, 4]
    print(mi_lista[indice])
except:
    print("Por favor ingrese un índice válido.")

Si ingresamos un índice inválido como 15, el resultado será:

Por favor ingrese un índice válido.

Porque la cláusula except se ejecuta. Sin embargo, si el valor es válido, el código en la cláusula try se ejecutaría normalmente.

Aquí tenemos otro ejemplo:

a = int(input("Ingrese a: "))
b = int(input("Ingrese b: "))

try:
    division = a / b
    print(division)
except:
    print("Por favor ingrese valores válidos.")

Si ingresamos los valores para a y b, el resultado será:

Ingrese a: 5
Ingrese b: 0

Por favor ingrese valores válidos.

Cómo detectar un tipo específico de excepción en Python

En lugar de detectar y manejar todas las excepciones posibles que pueden ocurrir en la cláusula try, podemos detectar y manejar un tipo específico de excepción. Solo necesitamos especificar el tipo de excepción luego de la palabra clave except:

try:
    <código que puede generar una excepción>
except <tipo de excepción>:
    <código para manejar la excepción si ocurre>

Por ejemplo:

indice = int(input("Ingrese el índice: "))

try:
    mi_lista = [1, 2, 3, 4]
    print(mi_lista[indice])
except IndexError: # Especifica el tipo de excepción.
    print("Por favor ingrese un índice válido.")
a = int(input("Ingrese a: "))
b = int(input("Ingrese b: "))

try:
    division = a / b
    print(division)
except ZeroDivisionError: # Especifica el tipo de excepción.
    print("Por favor ingrese valores válidos.")

Cómo asignarle un nombre al objeto de la excepción en Python

Podemos especificar un nombre para el objeto que representa la excepción. Para hacerlo, debemos asignarlo a una variable que luego podemos usar en la cláusula except. Esto nos permitirá acceder a su descripción y atributos.

Solo debemos añadir as <nombre de la variable>, de esta forma:

try:
    <código que puede generar una excepción>
except <tipo de excepción> as <nombre de la variable>:
    <código para manejar la excepción si ocurre>

Por ejemplo:

indice = int(input("Ingrese el índice: "))

try:
    mi_lista = [1, 2, 3, 4]
    print(mi_lista[indice])
except IndexError as e:
    print("Ocurrió una Excepción:", e)

Este es el resultado si ingresamos el valor 15 como el índice:

Ingrese el índice: 15
Ocurrió una Excepción: list index out of range

Este es otro ejemplo:

a = int(input("Ingrese a: "))
b = int(input("Ingrese b: "))

try:
    division = a / b
    print(division)
except ZeroDivisionError as err:
    print("Por favor ingrese valores válidos.", err)

Este es el resultado si ingresamos el valor 0 para b:

Por favor ingrese valores válidos. division by zero

try / except / else en Python

Podemos agregar la cláusula else a esta estructura luego de la cláusula except si queremos escoger qué ocurre cuando no se genera ninguna excepción durante la ejecución de la cláusula try:

try:
    <código que puede generar una excepción>
except:
    <código que maneja la excepción si ocurre>
else:
    <código que solo se ejecuta si no ocurre una excepción en try>

Por ejemplo:

a = int(input("Ingrese a: "))
b = int(input("Ingrese b: "))

try:
    division = a / b
    print(division)
except ZeroDivisionError as err:
    print("Por favor ingrese valores válidos.", err)
else:
    print("Ambos valores son válidos.")

Si ingresamos los valores 5 y 0 para a y b respectivamente, el resultado es:

Por favor ingrese valores válidos. division by zero

Pero si ambos valores son válidos, por ejemplo 5 y 4 para a y b respectivamente, la cláusula else se ejecuta luego de try y vemos este resultado:

1.25
Ambos valores son válidos.

try / except / else / finally en Python

También podemos agregar una cláusula finally si queremos ejecutar código que siempre debe ser ejecutado, incluso si ocurre una excepción durante la ejecución de la cláusula try.

Por ejemplo:

a = int(input("Ingrese a: "))
b = int(input("Ingrese b: "))

try:
    division = a / b
    print(division)
except ZeroDivisionError as err:
    print("Por favor ingrese valores válidos.", err)
else:
    print("Ambos valores son válidos.")
finally:
    print("¡finally!")

Si ambos valores son válidos, el resultado es el resultado de la división y el mensaje mostrado en la cláusula finally:

Ambos valores son válidos.
¡finally!

Y si se genera una excepción porque b es 0, vemos este resultado:

Por favor ingrese valores válidos. division by zero
¡finally!

La cláusula finally siempre se ejecuta.

💡 Dato: Esta cláusula puede ser usada, por ejemplo, para cerrar archivos que se estaban usando en la cláusula try, incluso si se genera una excepción.

🔸 Programación orientada a objetos en Python

En Programación Orientada a Objetos (POO), definimos clases que actúan como planos para crear objetos en Python con atributos y métodos (funciones asociadas a los objetos).

Esta es la sintaxis general para definir una clase en Python:

class <NombreDeLaClase>:

    <nombre_de_atributo_de_la_clase> = <valor>

    def __init__(self,<parametro1>, <parametro2>, ...):
        self.<atributo1> = <parametro1>
        self.<atributo2> = <parametro2>
        .
        .
        .
        # Tantos atributos como necesites.
    
   def <nombre_de_metodo>(self, <parametro1>, ...):
       <código>
       
   # Tantos métodos como necesites.

💡 Dato: self se refiere a la instancia de la clase (un objeto creado a partir del plano (clase) que definimos en el código).

Como puedes ver, una clase puede tener muchos elementos distintos, así que veámoslos en detalle:

Encabezado de la definición de una Clase

La primera línea de la definición de una clase tiene la palabra clave class y el nombre de la clase:

class Perro:
class Casa:
class ListaDeEspera:

💡 Dato: Si la clase hereda atributos y métodos de otra clase, veremos el nombre de esa clase entre paréntesis:

class Poodle(Perro):
class Camion(Vehiculo):
class Hermano(MiembroDeLaFamilia):

En Python, escribimos el nombre de la clase en Upper Camel Case (también conocido como Pascal Case), en el cual cada palabra comienza con una letra mayúscula. Por ejemplo: ListaDeEspera

__init__ y atributos de Instancias

En nuestro código vamos a usar clases para crear objetos en Python, al igual que podemos construir casas a partir de planos.

Los objetos tendrán los atributos que definimos en la clase. Usualmente, inicializamos los valores de estos atributos en __init__. Este es un método que se ejecuta automáticamente cuando creamos una instancia de la clase.

Esta es la sintaxis general del método:

def __init__(self, <parametro1>, <parametro2>, ...):
        self.<atributo1> = <parametro1>  # Atributo de Instancia
        self.<atributo2> = <parametro2>  # Atributo de Instancia
        .
        .
        .
        # Tantos atributos como necesites.

Especificamos tantos parámetros como sea necesario para personalizar los valores de los atributos del objeto que estamos creando.  

Aquí tenemos un ejemplo de una clase Perro con este método:

class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

💡 Dato: Nota los dos guiones bajo ubicados antes y después del nombre del método __init__.

Cómo crear una instancia

Para crear una instancia de la clase Perro, debemos especificar el nombre y la edad del perro para asignarle estos valores a sus atributos:

mi_perro = Perro("Nora", 10)

Genial. Ahora tenemos nuestra instancia lista para ser usada en el programa.

Algunas clases no requieren argumentos para crear una instancia. En ese caso, solo escribimos paréntesis vacíos al crear la instancia y solo incluimos self en la lista de parámetros de __init__.

Por ejemplo:

class Circulo:

    def __init__(self):
        self.radio = 1

Para crear una instancia:

>>> mi_circulo = Circulo()

💡 Dato: self es como un parámetro que actúa "detrás de escenas", así que incluso si lo ves en la definición del método, no debes considerarlo al momento de pasar los argumentos.

Argumentos por defecto para métodos

También podemos asignar valores por defecto para los atributos y aún así darle la opción al usuario que crea una instancia de personalizar el valor si lo desea.

En ese caso, escribiríamos <atributo>=<valor> en la lista de parámetros.

Este es un ejemplo:

class Circulo:

    def __init__(self, radio=1):
        self.radio = radio

Ahora podemos crear una instancia de la clase Circulo con el valor por defecto para el radio si omitimos el valor pero también podemos personalizarlo pasando un valor como argumento:

# Valor por Defecto
>>> mi_circulo1 = Circulo()

# Valor Personalizado
>>> mi_circulo2 = Circulo(5)

Cómo acceder al valor de un atributo de instancia

Para acceder al valor de un atributo de instancia, usamos esta sintaxis:

<variable_objeto>.<atributo>

Por ejemplo:

# Definición de la Clase
>>> class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

# Crear Instancia        
>>> mi_perro = Perro("Nora", 10)

# Atributos
>>> mi_perro.nombre
'Nora'

>>> mi_perro.edad
10

Cómo actualizar atributos de instancia

Para actualizar el valor de un atributo de instancia, usamos esta sintaxis:

<variable_objeto>.<atributo> = <valor_nuevo>

Por ejemplo:

>>> class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

        
>>> mi_perro = Perro("Nora", 10)

>>> mi_perro.name
'Nora'

# Actualizar el Atributo
>>> mi_perro.nombre = "Norita"

>>> mi_perro.nombre
'Norita'

Cómo remover un atributo de instancia

Para remover o eliminar un atributo de instancia, usamos esta sintaxis:

del <variable_objeto>.<atributo>

Por ejemplo:

>>> class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

        
>>> mi_perro = Perro("Nora", 10)

>>> mi_perro.nombre
'Nora'

# Remover el Atributo
>>> del mi_perro.nombre

>>> mi_perro.nombre
Traceback (most recent call last):
  File "<pyshell#77>", line 1, in <module>
    mi_perro.nombre
AttributeError: 'Perro' object has no attribute 'nombre'

Cómo eliminar una instancia

De igual forma, puedes eliminar una instancia con del:

>>> class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

        
>>> mi_perro = Perro("Nora", 10)

>>> mi_perro.nombre
'Nora'

# Eliminar la Instancia
>>> del mi_perro

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

Atributos públicos vs. atributos no públicos en Python

En Python no tenemos modificadores de acceso para restringir el acceso a los atributos de instancia, así que usamos convenciones de nomenclatura para especificarlo.

Añadiendo un guión bajo al inicio del nombre del atributo, podemos indicarle a otros desarrolladores que el atributo debería ser no público.

Por ejemplo:

class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre  # Atributo Público
        self._edad = edad     # Atributo No Público

La Documentación de Python menciona:

Usa un guión bajo al inicio solo para métodos y variables de instancia no públicos.

Siempre decide si los métodos de una clase y sus variables de instancia (en conjunto, denominados "atributos") deberían ser públicos o no públicos. Si tienes dudas, escoge no público. Es más fácil hacerlos publicos luego que hacer que un atributo público sea no público.

Los atributos no públicos son aquellos que no deberían ser usados por terceros. No se da ninguna garantía de que los atributos no públicos no serán cambiados o removidos.

Texto Original en Inglés:

Use one leading underscore only for non-public methods and instance variables.

Always decide whether a class's methods and instance variables (collectively: "attributes") should be public or non-public. If in doubt, choose non-public; it's easier to make it public later than to make a public attribute non-public.

Non-public attributes are those that are not intended to be used by third parties; you make no guarantees that non-public attributes won't change or even be removed. - source

Sin embargo, la documentación también menciona que:

No se usa el término "privado" porque ningún atributo es verdaderamente privado en Python (sin una cantidad innecesaria de trabajo).

Texto Original en Inglés:

We don't use the term "private" here, since no attribute is really private in Python (without a generally unnecessary amount of work). - source

💡 Dato: técnicamente, todavía podemos acceder y modificar los atributos aún si añadimos el guión bajo antes de sus nombres, pero no deberíamos hacerlo.

Atributos de clase en Python

Los atributos de clase son compartidos por todas las instancias de la clase. Todas tienen acceso a este atributo y son afectadas por cualquier cambio realizado a este tipo de atributo.

class Pero:

    # Atributos de Clase
    reino = "Animalia"
    especie = "C. familiaris"

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

💡 Dato: normalmente los definimos antes del método __init__.

Cómo acceder a un atributo de clase

Para acceder al valor de un atributo de clase, usamos esta sintaxis:

<NombreClase>.<atributo>

Por ejemplo:

>>> class Perro:

    reino = "Animalia"

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

        
>>> Perro.reino
'Animalia'

💡 Dato: También puedes usar esta sintaxis dentro de la clase.

Cómo actualizar un atributo de clase

Para actualizar un atributo de clase, usamos esta sintaxis:

<NombreClase>.<atributo> = <valor>

Por ejemplo:

>>> class Perro:

    reino = "Animalia"

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

        
>>> Perro.reino
'Animalia'

>>> Perro.reino = "Nuevo Reino"

>>> Perro.reino
'Nuevo Reino'

Cómo remover un atributo de clase

Usamos la sentencia del para eliminar un atributo de clase. Por ejemplo:

>>> class Perro:

    reino = "Animalia"

    def __init__(self, name, age):
        self.name = name
        self.age = age

>>> Perro.reino
'Animalia'
        
# Remover atributo de clase
>>> del Perro.reino

>>> Perro.reino
Traceback (most recent call last):
  File "<pyshell#88>", line 1, in <module>
    Perro.reino
AttributeError: type object 'Perro' has no attribute 'reino'

Cómo definir métodos

Los métodos representan la funcionalidad de las instancias de la clase.

💡 Datos: los métodos de instancia pueden trabajar con los atributos de la instancia que los está llamando con self.<atributo> en la definición del método.

Esta es la sintaxis básica de un método. Normalmente los definimos después del método  __init__:

class <NombreClase>:

    # Atributos de Clase

    # __init__

    def <nombre_del_método>(self, <parámetro1>, ...):
        <código>

Pueden tener cero, uno, o más parámetros si es necesario (¡igual que las funciones!) pero self siempre debe ser el primer parámetro de la lista de parámetros de un método de instancia.

Por ejemplo, aquí tenemos el método ladrar que no toma ningún parámetro (además de self):

class Perro:

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

    def ladrar(self):
        print(f"woof-woof. Soy {self.nombre}")

Para llamar al método, usamos esta sintaxis:

<variable_objeto>.<método>(<argumentos>)

Por ejemplo:

# Crear la instancia
>>> mi_perro = Perro("Nora", 10)

# Llamar al método
>>> mi_perro.ladrar()
woof-woof. Soy Nora

Aquí tenemos una clase Jugador con un método aumentar_velocidad que toma un parámetro:

class Jugador:

    def __init__(self, nombre):
        self.nombre = nombre
        self.velocidad = 50

    def aumentar_velocidad(self, valor):
        self.velocidad += valor

Para llamar al método:

# Crear una instancia        
>>> mi_jugador = Jugador("Nora")

# Verificar la velocidad inicial para ver el cambio.
>>> mi_jugador.velocidad
50

# Incrementar la velocidad.
>>> mi_jugador.aumentar_velocidad(5)

# Confirmar el cambio.
>>> mi_jugador.velocidad
55

💡 Dato: Para agregar más parámetros, solo debes separarlos con una coma. Se recomienda agregar un espacio después de la coma.

Propiedades, getters, y setters en Python

Los getters y setters son métodos que podemos definir para acceder y actualizar el valor de un atributo de instancia, respectivamente. Ellos funcionan como intermediarios para "proteger" los atributos de cambios directos.

Sin embargo, en Python normalmente usamos propiedades en lugar de getters y setters. Veamos cómo podemos usarlas.

Para definir una propiedad, escribimos un método con esta sintaxis:

@property
def <nombre_de_la_propiedad>(self):
    return self.<atributo>

Este método actuará como un getter, así que será llamado cuando intentemos acceder al valor del atributo.

También podemos definir un setter:

@<nombre_de_la_propiedad>.setter
def <nombre_de_la_propiedad>(self, <parametro>):
    self.<atributo> = <parametro>

Y un deleter para eliminar o remover el atributo:

@<nombre_de_la_propiedad>.deleter
def <nombre_de_la_propiedad>(self):
    del self.<atributo>

💡 Dato: puedes escribir el código que necesites para acceder al valor de un atributo, actualizarlo e incluso eliminar el atributo pero se recomienda que el código sea lo más sencillo posible.

Este es un ejemplo:

class Perro:

    def __init__(self, nombre):
        self._nombre = nombre

    @property
    def nombre(self):
        return self._nombre

    @nombre.setter
    def nombre(self, nombre_nuevo):
        self._nombre = nombre_nuevo

    @nombre.deleter
    def nombre(self):
        del self._nombre

Si agregamos llamadas a print() para visualizar el proceso, podemos ver que estos metodos son llamados cuando realizamos su operación correspondiente sobre la instancia:

>>> class Perro:

    def __init__(self, nombre):
        self._nombre = nombre

    @property
    def nombre(self):
        print("Llamando getter")
        return self._nombre

    @nombre.setter
    def nombre(self, nombre_nuevo):
        print("Llamando setter")
        self._nombre = nombre_nuevo

    @nombre.deleter
    def nombre(self):
        print("Llamando deleter")
        del self._nombre

        
>>> mi_perro = Perro("Nora")

>>> mi_perro.nombre
Llamando getter
'Nora'

>>> mi_perro.nombre = "Norita"
Llamando setter

>>> mi_perro.nombre
Llamando getter
'Norita'

>>> del mi_perro.nombre
Llamando deleter

🔹 Cómo trabajar con archivos en Python

Trabajar con archivos en muy importante para crear programas poderosos. Veamos cómo puedes hacerlo en Python.

Cómo leer archivos en Python

En Python, se recomienda usar una sentencia with para trabajar con archivos porque solo los mantiene abiertos mientras se necesitan y luego los cierra automáticamente cuando se completa el proceso.

Para leer un archivo, usamos esta sintaxis:

with open("<ubicación_del_archivo>") as <variable_archivo>:
    <código>

También podemos especificar que queremos abrir el archivo en modo de lectura con una "r":

with open("<ubicación_del_archivo>", "r") as <variable_archivo>:
    <código>

Pero este es el modo que se asigna por defecto para abrir un archivo, así que podemos omitirlo como en el primer caso.

Este es un ejemplo:

with open("frases_famosas.txt") as archivo:
    for linea in archivo:
        print(linea)

o...

with open("frases_famosas.txt", "r") as archivo:
    for linea in archivo:
        print(linea)

💡 Dato: ¡Sí! Podemos iterar sobre las líneas del archivo con un ciclo for.  La ubicación del archivo puede ser relativa al archivo de Python que se está ejecutando o puede ser absoluta.

Cómo actualizar un archivo con Python

Hay dos formas de escribir o agregar información a un archivo en Python. Puedes reemplazar todo el contenido del archivo antes de agregar el contenido nuevo, o agregar el contenido nuevo al final de contenido existente.

with open("<ubicación_del_archivo>", "w") as <variable_archivo>:
    <código>

Para reemplazar el contenido completamente, usamos el modo"w", así que pasamos esta cadena de caracteres como el segundo argumento de open().

Podemos llamar al método .write() del objeto del archivo y pasar el contenido que queremos incluir en el archivo como argumento.

Por ejemplo:

palabras = ["Genial", "Verde", "Python", "Código"]

with open("frases_famosas.txt", "w") as archivo:
    for palabra in palabras:
        archivo.write(palabra + "\n")

Cuando ejecutes el programa, un archivo nuevo será creado si ya no existía en la ubicación especificada.

Este será el contenido del archivo:

Genial
Verde
Python
Código

Cómo agregar contenido a un archivo en Python

Sin embargo, si quieres agregar contenido al contenido existente, entonces debes usar el modo  "a":

with open("<ubicación_del_archivo>", "a") as <variable_archivo>:
    <código>

Por ejemplo:

palabras = ["Genial", "Verde", "Python", "Código"]

with open("frases_famosas.txt", "a") as archivo:
    for palabra in palabras:
        archivo.write(word + "\n")

Este pequeño cambio mantiene el contenido del archivo y añade el contenido nuevo al final del archivo.

Si volvemos a ejecutar el programa, vamos que las palabras se añaden al final del archivo:

Genial
Verde
Python
Código
Genial
Verde
Python
Código

Cómo eliminar un archivo en Python

Para eliminar un archivo con nuestro programa de Python, podemos usar el módulo os . Se recomienda verificar con un condicional si el archivo existe antes de llamar a la función remove() de este módulo:

import os

if os.path.exists("<ubicación_del_archivo>"):
  os.remove("<ubicación_del_archivo>")
else:
  <código>

Por ejemplo:

import os

if os.path.exists("frases_famosas.txt"):
  os.remove("frases_famosas.txt")
else:
  print("Este archivo no existe.")

Quizás hayas notado que la primera línea dice import os. Esta es una sentencia de importación. Veamos por qué son útiles y cómo puedes trabajar con ellas en Python.

🔸 Sentencias de importación en Python

Se recomienda organizar tu código en varios archivos a medida que tu programa crece en complejidad y en tamaño. Pero debemos encontrar una forma de combinar los archivos para que el programa funcione correctamente. Eso es exactamente lo que hacen las sentencias de importación.

Al escribir una sentencia de importación, podemos importar un módulo (un archivo que contiene definiciones y sentencias de Python) en otro archivo.

Hay varias alternativas para escribir sentencias de importación:

Primera alternativa:

import <nombre_módulo>

For example:

import math

💡 Tip: math es un módulo incorporado (built-in) de Python que se instala automáticamente cuando instalas Python.

Si usamos esta sentencia de importación, debemos incluir el nombre del módulo antes del nombre de la función o del elemento al cual nos estamos refiriendo en nuestro código:

>>> import math
>>> math.sqrt(25)
5.0

Estamos especificando explícitamente a cuál módulo pertenece la función que estamos llamando.

Segunda alternativa:

import <módulo> as <nombre_nuevo_para_módulo>

Por ejemplo:

import math as m

En nuestro código podemos usar el nombre nuevo que asignamos en la sentencia de importación en lugar del nombre original del módulo:

>>> import math as m
>>> m.sqrt(25)
5.0

Tercera alternativa:

from <módulo> import <elemento>

Por ejemplo:

from math import sqrt

Con esta sentencia de importación, podemos llamar a la función directamente sin especificar el nombre del módulo:

>>> from math import sqrt
>>> sqrt(25)
5.0

Cuarta alternativa:

from <módulo> import <elemento> as <nombre_nuevo>

Por ejemplo:

from math import sqrt as raiz_cuadrada

Con esta sentencia de importación podemos asignar un nombre nuevo al elemento que importamos del módulo:

>>> from math import sqrt as raiz_cuadrada
>>> raiz_cuadrada(25)
5.0

Quinta alternativa:

from <módulo> import *

Esta sentencia de importación importa todos los elementos del módulo y puedes referirte a ellos directamente por su nombre, sin especificar el nombre del módulo.

Por ejemplo:

>>> from math import *

>>> sqrt(25)
5.0

>>> factorial(5)
120

>>> floor(4.6)
4

>>> gcd(5, 8)
1

💡 Dato: Este tipo de sentencia de importación se llama "Wildcard" y puede hacer que sea más dificil identificar el módulo del cual provienen las funciones y elementos usados en el programa, especialmente cuando se importan elementos de varios módulos.

Según la Guía de Estilo de Python:

Las Sentencias de Importación "Wildcard" (from <module> import *) deben ser evitadas porque no son claras para especificar qué nombres están presentes en el "namespace", lo cual puede confundir tanto a los lectores como a herramientas automatizadas.

Texto original en inglés:

Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.

🔹 Comprensión de listas y diccionarios en Python

Una capacidad genial de Python que debes conocer es la compresión de listas y diccionarios. Esta es una forma de crear listas y diccionarios de forma más concisa y compacta.

Comprensión de listas en Python

La sintaxis usada para definir comprensiones de listas generalmente sigue uno de los siguientes patrones:

[<valor_a_incluir> for <variable> in <secuencia>]
[<valor_a_incluir> for <var1> in <secuencia1> for <var2> in <secuencia2>]
[<valor_a_incluir> for <variable> in <secuencia> if <condición>]
[<valor> for <var1> in <secuencia1> for <var2> in <secuencia2> if <condición>]

💡 Dato: solo deberías usarla cuando no dificulta la lectura y compresión de tu código.

Aquí tenemos algunos ejemplos:

>>> [i for i in range(4, 15)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

>>> [chr(i) for i in range(67, 80)]
['C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O']

>>> [i**3 for i in range(2, 5)]
[8, 27, 64]

>>> [i + j for i in range(5, 8) for j in range(3, 6)]
[8, 9, 10, 9, 10, 11, 10, 11, 12]

>>> [k for k in range(3, 35) if k % 2 == 0]
[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34]

>>> [i * j for i in range(2, 6) for j in range(3, 7) if i % j == 0]
[9, 16, 25]

Comprensión de listas vs. expresiones generadoras en Python

La comprensión de listas se define con corchetes [] mientras que las expresiones generadoras se definen con paréntesis (). Ambas se ven similares inicialmente pero son diferentes.

Veamos por qué:

  • La Comprensión de Listas genera la secuencia completa inmediatamente y la guarda en memoria.
  • Las Expresiones Generadoras generan los elementos uno por uno cuando son requeridos. No guarda toda la secuencia en memoria de una sola vez, sino que genera y guarda un solo elemento a la vez.

Podemos verificar esta diferencia con el módulo sys. En el siguiente ejemplo, puedes ver que su tamaño en memoria es muy diferente:

>>> import sys
>>> sys.getsizeof([i for i in range(500)])
2132
>>> sys.getsizeof((i for i in range(500)))
56

Podemos usar las expresiones generadoras para iterar en un ciclo for y obtener los elementos uno por uno para cada iteración del ciclo. Pero si necesitamos guardar todos los elementos en memoria de una vez, entonces deberíamos usar comprensión de listas.

Comprensión de diccionarios en Python

Ahora veamos comprensión de diccionarios. La sintaxis básica que debemos usar para generar comprensión de diccionarios es:

{<valor_clave>: <valor> for <variable> in <secuencia>}
{<valor_clave>: <valor> for <variable> in <secuencia> if <condición>}

Aquí tenemos algunos ejemplos:

>>> {num: num**3 for num in range(3, 15)}
{3: 27, 4: 64, 5: 125, 6: 216, 7: 343, 8: 512, 9: 729, 10: 1000, 11: 1331, 12: 1728, 13: 2197, 14: 2744}

>>> {x: x + y for x in range(4, 8) for y in range(3, 7)}
{4: 10, 5: 11, 6: 12, 7: 13}

Este es un ejemplo con un condicional en el que tomamos un diccionario y creamos uno nuevo que solo contiene los estudiantes que aprobaron con una nota mayor o igual que 60:

>>> grades = {"Nora": 78, "Gino": 100, "Talina": 56, "Elizabeth": 45, "Lulu": 67}

>>> approved_students = {student: grade for (student, grade) in grades.items() if grade >= 60}

>>> approved_students
{'Nora': 78, 'Gino': 100, 'Lulu': 67}

Espero que te haya gusta mi artículo y que te haya sido de utilidad. Ahora sabes cómo trabajar con las estructuras y los elementos más importantes de Python. Te invito a seguirme en Twitter @EstefaniaCassN.