Guía completa de Python 2025 (3/3): clases, objetos y temas avanzados

Guía completa de Python 2025 (3/3): clases, objetos y temas avanzados

En las partes anteriores vimos los tipos de datos y los operadores, control de flujo y funciones. En este último capítulo vemos las **clases y objetos**, los **iteradores**, el **alcance de variables**, los **módulos y paquetes**, el manejo de errores con **try... except**, las **palabras reservadas** y el **Zen de Python**.

📚 **Esta entrada es parte de la serie _Guía completa de Python_**, dividida en tres capítulos que se leen en orden:

> * Parte 1: Tipos de datos

* Parte 2: Operadores, control de flujo y funciones

* 👉 **Parte 3: Clases, objetos y temas avanzados**

7. Clases y objetoslink image 1

Python es un lenguaje de programación orientado a objetos. Casi todo en Python es un objeto, con sus atributos y métodos.

Una clase es como un constructor de objetos o un "plano" para crear objetos.

Para crear una clase se usa la palabra reservada class

	
< > Input
Python
class Clase:
variable = 'MaximoFN'
Copied

Una vez creada la clase, se puede crear un objeto de dicha clase

	
< > Input
Python
objeto = Clase()
Clase.variable
Copied
>_ Output
			
'MaximoFN'

Normalmente las clases tienen una función inicial, que se ejecuta cuando se crea un objeto de la clase. Esta función se denomina *dunder init* y se escribe __init__(). A la función *dunder init* se le tiene que pasar siempre la variable self, que indica la propia clase, y a continuación, las variables que se quieran pasar

Con esta función se suelen inicializar las variables de las clases, o se ejecuta el código que se necesita cuando se crea un objeto de la clase

	
< > Input
Python
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
objeto_persona = Persona("Miguel", 36)
print(objeto_persona.nombre)
print(objeto_persona.edad)
Copied
>_ Output
			
Miguel
36

Además de la función inicial *dunder init*, se pueden crear más funciones. A estas funciones se les llama *métodos* de la clase. A estos *métodos* siempre hay que pasarles la variable self

	
< > Input
Python
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def saludar(self):
print(f'Hola mi nombre es {self.nombre} y tengo {self.edad} años')
objeto_persona = Persona("Miguel", 36)
objeto_persona.saludar()
Copied
>_ Output
			
Hola mi nombre es Miguel y tengo 36 años

La variable self no tiene por qué ser llamada self, puede tener cualquier nombre, pero dentro de cada clase tiene que ser siempre el mismo. Pero por convenio, se suele usar self

	
< > Input
Python
class Persona:
def __init__(yo_mismo, nombre, edad):
yo_mismo.nombre = nombre
yo_mismo.edad = edad
def saludar(yo_mismo):
print(f'Hola mi nombre es {yo_mismo.nombre} y tengo {yo_mismo.edad} años')
objeto_persona = Persona("Miguel", 36)
objeto_persona.saludar()
Copied
>_ Output
			
Hola mi nombre es Miguel y tengo 36 años

Se pueden modificar las variables de los objetos

	
< > Input
Python
objeto_persona.nombre = 'Marta'
objeto_persona.saludar()
Copied
>_ Output
			
Hola mi nombre es Marta y tengo 36 años

Incluso eliminarlas

	
< > Input
Python
del objeto_persona.nombre
Copied

También se puede eliminar el objeto entero

	
< > Input
Python
del objeto_persona
Copied

Si, por ejemplo, queremos hacer la estructura de la clase, pero no queremos, de momento, codificar el interior, podemos usar pass

	
< > Input
Python
class Persona:
pass
objeto_persona = Persona()
Copied

7.1. Herencialink image 2

La herencia nos permite definir una clase que herede todos los métodos y propiedades de otra clase.

La **clase padre** es la clase de la que se hereda, también llamada **clase base**.

La **clase hija** es la clase que hereda de otra clase, también llamada **clase derivada**.

Creamos una clase padre

	
< > Input
Python
class Persona:
def __init__(self, nombre, apellido):
self.nombre = nombre
self.apellido = apellido
def imprimir_nombre(self):
print(f'Me llamo {self.nombre} {self.apellido}')
objeto_padre = Persona("Laura", "Perez")
objeto_padre.imprimir_nombre()
Copied
>_ Output
			
Me llamo Laura Perez

Para crear la clase hija hay que indicar entre paréntesis, a la hora de declarar la clase, de qué clase hereda

	
< > Input
Python
class Estudiante(Persona):
pass
Copied

Y al momento de crear el objeto de la clase hija, se le pasan los parámetros que la clase padre necesita

	
< > Input
Python
objeto_hijo = Estudiante("Mariano", "Sanz")
objeto_hijo.imprimir_nombre()
Copied
>_ Output
			
Me llamo Mariano Sanz

Hasta ahora la clase hija ha heredado las funciones de la clase padre, pero podemos modificarlas reescribiéndolas. Por ejemplo reescribiendo la función *dunder init*.

Si se reescribe la función *dunder init*, si queremos que se llame a la función *dunder init* de la clase padre hay que llamarla.

Para esto hay dos maneras, una es mediante el nombre de la clase padre. En este caso, hay que pasarle la variable self.

	
< > Input
Python
class Estudiante(Persona):
def __init__(self, nombre, apellido):
Persona.__init__(self, nombre, apellido)
objeto_hijo = Estudiante("Mariano", "Sanz")
objeto_hijo.imprimir_nombre()
Copied
>_ Output
			
Me llamo Mariano Sanz

Otra forma es mediante super(), en este caso no hace falta pasarle la variable self

	
< > Input
Python
class Estudiante(Persona):
def __init__(self, nombre, apellido):
super().__init__(nombre, apellido)
objeto_hijo = Estudiante("Mariano", "Sanz")
objeto_hijo.imprimir_nombre()
Copied
>_ Output
			
Me llamo Mariano Sanz

Al modificar las funciones se puede agregar código nuevo

	
< > Input
Python
class Estudiante(Persona):
def __init__(self, nombre, apellido, curso):
Persona.__init__(self, nombre, apellido)
self.curso = curso
def imprimir_nombre(self):
Persona.imprimir_nombre(self)
print(f'Estoy en el curso número {self.curso}')
objeto_hijo = Estudiante("Mariano", "Sanz", 4)
objeto_hijo.imprimir_nombre()
Copied
>_ Output
			
Me llamo Mariano Sanz
Estoy en el curso número 4

Por último, se pueden agregar nuevos métodos

	
< > Input
Python
class Estudiante(Persona):
def __init__(self, nombre, apellido, curso):
Persona.__init__(self, nombre, apellido)
self.curso = curso
def imprimir_nombre(self):
Persona.imprimir_nombre(self)
print(f'Estoy en el curso número {self.curso}')
def imprimir_estudiante(self):
print(f"Soy un estudiante del curso número {self.curso}")
objeto_hijo = Estudiante("Mariano", "Sanz", 4)
objeto_hijo.imprimir_nombre()
objeto_hijo.imprimir_estudiante()
Copied
>_ Output
			
Me llamo Mariano Sanz
Estoy en el curso número 4
Soy un estudiante del curso número 4

7.2. Sobrecarga de operadoreslink image 3

Podemos definir operaciones básicas, como la suma, entre varios objetos de una clase. Por ejemplo, si tenemos una clase que representa un vector, podemos definir la suma y la multiplicación entre objetos de dicha clase

	
< > Input
Python
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, other):
return Vector(self.x * other.x, self.y * other.y)
def __str__(self):
return f"Vector ({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector (4, 6)
print(v1 * v2) # Vector (3, 8)
Copied
>_ Output
			
Vector (4, 6)
Vector (3, 8)

Todas las posibles sobrecargas de operadores son:

  • __add__(self, other): sobrecarga el operador de suma (+).
  • __sub__(self, other): sobrecarga el operador de resta (-).
  • __mul__(self, other): sobrecarga el operador de multiplicación (*).
  • __truediv__(self, other): sobrecarga el operador de división (/).
  • __floordiv__(self, other): sobrecarga el operador de división de redondeo (//).
  • __mod__(self, other): sobrecarga el operador de módulo (%).
  • __divmod__(self, other): sobrecarga la función divmod().
  • __pow__(self, other): sobrecarga el operador de potencia (**).
  • __lshift__(self, other): sobrecarga el operador de desplazamiento a la izquierda (<<).
  • __rshift__(self, other): sobrecarga el operador de desplazamiento a la derecha (>>).
  • __and__(self, other): sobrecarga el operador de and (&).
  • __or__(self, other): sobrecarga el operador de or (|).
  • __xor__(self, other): sobrecarga el operador de xor (^).
  • __lt__(self, other): sobrecarga el operador de comparación menor que (<).
  • __le__(self, other): sobrecarga el operador de comparación menor o igual que (<=).
  • __eq__(self, other): sobrecarga el operador de comparación igual a (==).
  • __ne__(self, other): sobrecarga el operador de comparación diferente a (!=).
  • __gt__(self, other): sobrecarga el operador de comparación mayor que (>).
  • __ge__(self, other): sobrecarga el operador de comparación mayor o igual que (>=).
  • __neg__(self): sobrecarga el operador de negación (-).
  • __pos__(self): sobrecarga el operador de posición (+).
  • __abs__(self): sobrecarga la función abs().
  • __invert__(self): sobrecarga el operador de inversión (~).
  • __complex__(self): sobrecarga la función complex().
  • __int__(self): sobrecarga la función int().
  • __float__(self): sobrecarga la función float().

7.3. Iteradores personalizadoslink image 4

Como hemos visto en el apartado 2 (Tipos de datos de Python), existen algunos tipos de datos sobre los que se puede iterar. Pero podemos hacernos nuestra propia clase iterable, siempre que tenga las funciones __len__ y __getitem__

	
< > Input
Python
class custonIterator:
def __init__(self, n):
self.items = [i for i in range(n)]
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
iterator = custonIterator(10)
print(len(iterator)) # 10
print(iterator[0]) # 0
print(iterator[1]) # 1
Copied
>_ Output
			
10
0
1

Ahora podemos iterar con el objeto de nuestra clase con bucles for, por ejemplo

	
< > Input
Python
for i in iterator:
print(i, end=" ") # 0 1 2 3 4 5 6 7 8 9
Copied
>_ Output
			
0 1 2 3 4 5 6 7 8 9

7.4. Llamada a objetos como funcioneslink image 5

Nos puede interesar llamar a un objeto de una función como si fuera una clase. Esto se puede conseguir agregando la función __call__ a la clase

	
< > Input
Python
class potencia:
def __init__(self, base):
self.base = base
def __call__(self, potencia):
return self.base ** potencia
potencia_cuadrado = potencia(2)
print(potencia_cuadrado(3)) # 8
Copied
>_ Output
			
8

7.5. Atributos y funciones privadoslink image 6

Cuando creamos una clase, podemos hacer que algunos atributos o funciones sean privados y no se pueda acceder desde fuera de la clase, para ello hay que añadir __ antes del atributo o método

	
< > Input
Python
class Privados:
def __init__(self):
self.publico = "Soy público"
self.__privado = "Soy privado"
def getPrivado(self):
return self.__privado
def setPrivado(self, valor):
self.__privado = valor
def __funcion_privada(self):
return "Soy una función privada"
def funcion_publica(self):
return self.__funcion_privada()
privados = Privados()
print("Acceso al atributo publico: ", end="")
try:
print(f"{privados.publico}")
except:
print(" No se puede acceder al atributo privado")
print("Acceso al atributo privado: ", end="")
try:
print(f"{privados.__privado}")
except:
print(" No se puede acceder al atributo privado")
print("Acceso al atributo privado mediante el accesor: ", end="")
try:
print(f"{privados.getPrivado()}")
except:
print(" No se puede acceder al atributo privado mediante el accesor")
print("Llamada a la función privada: ", end="")
try:
print(f"{privados.__funcion_privada()}")
except:
print(" No se puede llamar a la función privada")
print("Llamada a la función pública: ", end="")
try:
print(f"{privados.funcion_publica()}")
except:
print(" No se puede llamar a la función pública")
Copied
>_ Output
			
Acceso al atributo publico: Soy público
Acceso al atributo privado: No se puede acceder al atributo privado
Acceso al atributo privado mediante el accesor: Soy privado
Llamada a la función privada: No se puede llamar a la función privada
Llamada a la función pública: Soy una función privada

8. Iteradoreslink image 7

Un iterador es un objeto que contiene un número contable de valores.

Un iterador es un objeto sobre el que se puede iterar, lo que significa que puede recorrer todos los elementos.

Técnicamente, en Python, un iterador es un objeto que implementa el protocolo del iterador, que consta de los métodos __iter__() y __next__().

Las listas, tuplas, diccionarios y conjuntos son todos objetos iterables. Son contenedores iterables de los que se puede obtener un iterador.

Todos estos objetos tienen un método iter() que se usa para obtener un iterador:

	
< > Input
Python
tupla = ("manzana", "plátano", "cereza")
iterable = iter(tupla)
print(next(iterable))
print(next(iterable))
print(next(iterable))
Copied
>_ Output
			
manzana
plátano
cereza
	
< > Input
Python
string = "plátano"
iterable = iter(string)
print(next(iterable), end=' ')
print(next(iterable), end=' ')
print(next(iterable), end=' ')
print(next(iterable), end=' ')
print(next(iterable), end=' ')
print(next(iterable), end=' ')
print(next(iterable), end=' ')
Copied
>_ Output
			
p l á t a n o

El bucle for en realidad crea un objeto iterador y ejecuta el método next() en cada iteración.

	
< > Input
Python
tupla = ("manzana", "plátano", "cereza")
for x in tupla:
print(x)
Copied
>_ Output
			
manzana
plátano
cereza
	
< > Input
Python
string = "plátano"
for x in string:
print(x, end=' ')
Copied
>_ Output
			
p l á t a n o

8.1. Crear un objeto iteradorlink image 8

Para crear un objeto/clase como iterador, hay que implementar los métodos __iter__() y __next__().

	
< > Input
Python
class Numeros:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
objeto_iterador = Numeros()
iterador = iter(objeto_iterador)
print(next(iterador), end=' ')
print(next(iterador), end=' ')
print(next(iterador), end=' ')
print(next(iterador), end=' ')
print(next(iterador), end=' ')
Copied
>_ Output
			
1 2 3 4 5

El ejemplo anterior continuaría para siempre si tuviera suficientes llamadas a next(), o si se usara en un bucle for.

Para evitar que la iteración continúe para siempre, podemos usar la declaración StopIteration.

En el método __next__(), podemos agregar una condición de terminación para generar un error si la iteración se realiza un número específico de veces:

	
< > Input
Python
class Numeros:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a &lt;= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
objeto_iterador = Numeros()
iterador = iter(objeto_iterador)
for x in iterador:
print(x, end=' ')
Copied
>_ Output
			
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

8.2. Iterar obteniendo el índice y el valorlink image 9

Podemos iterar por un objeto iterable obteniendo en cada iteración su índice y su valor mediante el método enumerate()

	
< > Input
Python
string = "MaximoFN"
for index, valor in enumerate(string):
print(f"En la posición {index}, está el caracter {valor}")
Copied
>_ Output
			
En la posición 0, está el caracter M
En la posición 1, está el caracter a
En la posición 2, está el caracter x
En la posición 3, está el caracter i
En la posición 4, está el caracter m
En la posición 5, está el caracter o
En la posición 6, está el caracter F
En la posición 7, está el caracter N

8.3. Iterar simultáneamente sobre dos objetos iterableslink image 10

Si tenemos dos objetos iterables, de la misma longitud, podemos iterar por los dos a la vez mediante el método zip()

	
< > Input
Python
string1 = 'MaximoFN__'
string2 = 'PythonPost'
if len(string1) == len(string2):
for valor1, valor2 in zip(string1, string2):
print(f"En el primer string hay {valor1}, en el segundo string hay {valor2}")
Copied
>_ Output
			
En el primer string hay M, en el segundo string hay P
En el primer string hay a, en el segundo string hay y
En el primer string hay x, en el segundo string hay t
En el primer string hay i, en el segundo string hay h
En el primer string hay m, en el segundo string hay o
En el primer string hay o, en el segundo string hay n
En el primer string hay F, en el segundo string hay P
En el primer string hay N, en el segundo string hay o
En el primer string hay _, en el segundo string hay s
En el primer string hay _, en el segundo string hay t

9. Alcance de variableslink image 11

Una variable solo está disponible dentro de la región en la que se crea. A esto se le llama *alcance*

9.1. Alcance locallink image 12

Una variable creada dentro de una función pertenece al ámbito local de esa función y solo se puede usar dentro de esa función.

	
< > Input
Python
def funcion():
x = 300
print(x)
funcion()
Copied
>_ Output
			
300

La variable x no está disponible fuera de la función, pero está disponible para cualquier función dentro de ella

	
< > Input
Python
def funcion():
x = 300
def funcion_interna():
print(x)
funcion_interna()
funcion()
Copied
>_ Output
			
300

9.2. Alcance globallink image 13

Una variable creada en el cuerpo principal del código Python es una variable global y pertenece al ámbito global.

Las variables globales están disponibles desde cualquier ámbito, global y local.

	
< > Input
Python
x = 300
def funcion():
print(f'Ámbito local: {x}')
funcion()
print(f'Ámbito global: {x}')
Copied
>_ Output
			
Ámbito local: 300
Ámbito global: 300

Si se crean dos variables, una global y otra local, las dos con el mismo nombre, Python las creará como dos variables distintas

	
< > Input
Python
x = 300
def funcion():
x = 200
print(f'Variable local: {x}')
funcion()
print(f'Variable global: {x}')
Copied
>_ Output
			
Variable local: 200
Variable global: 300

Si se necesita crear una variable global, pero está declarada en el ámbito local, se puede usar la palabra clave global.

La palabra clave global hace que la variable sea global.

	
< > Input
Python
def funcion():
global x
x = 300
funcion()
print(f'Variable global: {x}')
Copied
>_ Output
			
Variable global: 300

Además, el uso de la palabra clave global permite realizar un cambio en una variable global dentro de una función.

	
< > Input
Python
x = 300
def funcion():
global x
x = 200
funcion()
print(f'Variable global: {x}')
Copied
>_ Output
			
Variable global: 200

10. Móduloslink image 14

Un módulo es un archivo que contiene un conjunto de funciones que desea incluir en su aplicación.

Para crear un módulo, simplemente guarde el código que desea en un archivo con la extensión de archivo .py

Tip: En los cuadernos Jupyter (Colab es un cuaderno Jupyter en línea), si escribimos el carácter ! antes de un comando podremos ejecutar comandos de terminal

Primero vamos a ver en qué directorio estamos, para eso usamos el comando pwd (*print working directory*)

	
< > Input
Python
!pwd
Copied
>_ Output
			
/home/wallabot/Documentos/web/portafolio/posts

Vamos a crear una carpeta para crear nuestros modulos con el comando mkdir (make directory)

	
< > Input
Python
!mkdir introduccion_python
Copied

A continuación veamos qué archivos hay en nuestra carpeta. Esto lo haremos mediante el comando ls (*list*)

	
< > Input
Python
!ls introduccion_python
Copied

Vemos que está vacía, creamos un nuevo archivo .py en el que vamos a crear nuestro módulo

	
< > Input
Python
%%writefile introduccion_python/modulo1.py
def funcion_del_modulo(nombre):
print("Hola, " + nombre)
Copied
>_ Output
			
Writing introduccion_python/modulo1.py

Volvemos a ver qué archivos hay en nuestra carpeta

	
< > Input
Python
!ls introduccion_python
Copied
>_ Output
			
modulo1.py __pycache__

Vemos que se ha creado un archivo módulo1.py. Ya podemos usarlo

Para usar un módulo externo hay que usar la palabra import. Para usar las funciones del módulo hay que poner primero el nombre del módulo, un . y, a continuación, el nombre de la función que se quiere usar

	
< > Input
Python
import introduccion_python.modulo1
introduccion_python.modulo1.funcion_del_modulo('MaximoFN')
Copied
>_ Output
			
Hola, MaximoFN

Si queremos que dentro de nuestro código, el módulo tenga un nombre determinado, podemos usar la palabra as

	
< > Input
Python
import introduccion_python.modulo1 as mod1
mod1.funcion_del_modulo('MaximoFN')
Copied
>_ Output
			
Hola, MaximoFN

Si el módulo tiene varias funciones, pero solo queremos importar una, podemos hacerlo mediante el uso de las palabras from e import. La forma sería

from <modulo> import <funcion>

En este caso no hace falta indicar el nombre del módulo al llamar a la función

	
< > Input
Python
%%writefile introduccion_python/modulo2.py
def funcion1_del_modulo(nombre):
print("Hola, " + nombre + ", funcion 1")
def funcion2_del_modulo(nombre):
print("Hola, " + nombre + ", funcion 2")
def funcion3_del_modulo(nombre):
print("Hola, " + nombre + ", funcion 3")
Copied
>_ Output
			
Writing introduccion_python/modulo2.py
	
< > Input
Python
from introduccion_python.modulo2 import funcion2_del_modulo
funcion2_del_modulo('MaximoFN')
Copied
>_ Output
			
Hola, MaximoFN, funcion 2

No solo podemos usar módulos creados por nosotros, sino módulos ya instalados (built-in modules)

Por ejemplo, podemos usar el módulo platform

	
< > Input
Python
import platform
x = platform.system()
x
Copied
>_ Output
			
'Linux'

10.1. Entry points: archivos como módulos y no como scriptslink image 15

Vamos ahora a crear un archivo llamado módulo3.py

	
< > Input
Python
%%writefile introduccion_python/modulo3.py
print("Hola desde modulo3")
def funcion_del_modulo():
return "Hola desde la función del modulo3"
Copied
>_ Output
			
Overwriting introduccion_python/modulo3.py

Si ahora importamos modulo3.py para usar la función funcion_del_modulo veamos qué ocurre

	
< > Input
Python
import introduccion_python.modulo3 as mod3
print(mod3.funcion_del_modulo())
Copied
>_ Output
			
Hola desde modulo3
Hola desde la función del modulo3

Vemos que se ha ejecutado el print de modulo3.py, pero no es lo que nosotros queríamos, esto es debido a que al llamarse el archivo modulo3.py Python lo ejecuta como un script

Pero ¿qué ocurre si queremos ejecutar introduccion_python/main.py como un script?

	
< > Input
Python
!python introduccion_python/modulo3.py
Copied
>_ Output
			
Hola desde modulo3

Vemos que solo se ejecuta el print, pero no la función funcion_del_modulo. Si queremos tener la dualidad de funcionalidad del archivo modulo3.py, es decir, que podamos importarlo desde otro módulo sin que se ejecute como un script y ejecutarlo solo, y que se ejecute la función que nosotros queremos, se usa un entry point. Esto es, usar la condición if __name__ == '__main__': y, a continuación, indicar qué queremos que se ejecute. Veámoslo con un ejemplo, voy a reescribir el archivo modulo3.py

	
< > Input
Python
%%writefile introduccion_python/modulo3.py
print("Hola desde modulo3")
def funcion_del_modulo():
return "Hola desde la función del modulo3"
if __name__ == "__main__":
funcion_del_modulo()
Copied
>_ Output
			
Overwriting introduccion_python/modulo3.py

Si ahora llamo a main.py desde otro módulo, ya no se ejecutará el print

	
< > Input
Python
import introduccion_python.modulo3 as mod3
print(mod3.funcion_del_modulo())
Copied
>_ Output
			
Hola desde la función del modulo3

Y si lo ejecuto como un script independiente, se ejecutará la función función_del_modulo

	
< > Input
Python
!python introduccion_python/modulo3.py
Copied
>_ Output
			
Hola desde modulo3

11. Paqueteslink image 16

En Python podemos crearnos nuestros propios paquetes, para ello creamos una carpeta con el nombre del paquete

	
< > Input
Python
!mkdir mi_paquete_de_python
Copied

Creamos ahora dos archivos dentro

	
< > Input
Python
!touch mi_paquete_de_python/modulo1.py mi_paquete_de_python/modulo2.py
Copied

Y escribimos en ellos

	
< > Input
Python
%%writefile mi_paquete_de_python/modulo1.py
def funcion1():
print("Hola desde la función 1 del módulo 1")
def funcion2():
print("Hola desde la función 2 del módulo 1")
Copied
>_ Output
			
Overwriting mi_paquete_de_python/modulo1.py
	
< > Input
Python
%%writefile mi_paquete_de_python/modulo2.py
def funcion1():
print("Hola desde la función 1 del módulo 2")
def funcion2():
print("Hola desde la función 2 del módulo 2")
Copied
>_ Output
			
Overwriting mi_paquete_de_python/modulo2.py

Ahora podemos llamar a las funciones de nuestro paquete

	
< > Input
Python
from mi_paquete_de_python import modulo1 as mod1
from mi_paquete_de_python import modulo2 as mod2
mod1.funcion1()
mod1.funcion2()
mod2.funcion1()
mod2.funcion2()
Copied
>_ Output
			
Hola desde la función 1 del módulo 1
Hola desde la función 2 del módulo 1
Hola desde la función 1 del módulo 2
Hola desde la función 2 del módulo 2

Pero ¿qué ocurre si nuestro paquete tiene decenas de archivos con funciones que queremos usar? Tendríamos que importar todos los archivos uno a uno. Para evitar esto, se puede crear un archivo __init__.py dentro del paquete donde se haga toda esta importación de archivos

	
< > Input
Python
!touch mi_paquete_de_python/__init__.py
Copied
	
< > Input
Python
%%writefile mi_paquete_de_python/__init__.py
import modulo1
import modulo2
Copied
>_ Output
			
Overwriting mi_paquete_de_python/__init__.py

Ahora podemos solamente importar nuestro paquete, que ya internamente se han importado todos los módulos

	
< > Input
Python
import mi_paquete_de_python as mi_paquete
mi_paquete.modulo1.funcion1()
mi_paquete.modulo1.funcion2()
mi_paquete.modulo2.funcion1()
mi_paquete.modulo2.funcion2()
Copied
>_ Output
			
Hola desde la función 1 del módulo 1
Hola desde la función 2 del módulo 1
Hola desde la función 1 del módulo 2
Hola desde la función 2 del módulo 2

De esta manera solo tenemos que hacer un import

12. Try... exceptlink image 17

Cuando ocurre un error, o una excepción como se llama realmente, Python normalmente lo capturará y generará un mensaje de error.

Estas excepciones se pueden manejar usando las declaraciones try y except

	
< > Input
Python
try:
print(variable_no_declarada)
except:
print("Ha ocurrido una excepción")
Copied
>_ Output
			
Ha ocurrido una excepción

Dado que el bloque try genera un error, entonces se ejecutará el bloque except

Sin el bloque try, el programa se bloquearía y generaría un error

Se pueden definir tantos bloques de excepción como se desee, por ejemplo, si se quiere ejecutar un bloque de código especial para un tipo de error especial

	
< > Input
Python
try:
print(variable_no_declarada)
except NameError:
print("La variable 'variable_no_declarada' no está definida")
except:
print("Algo inesperado ha ocurrido")
Copied
>_ Output
			
La variable 'variable_no_declarada' no está definida

Se puede usar la palabra else para indicar el caso en el que no se haya producido un error

	
< > Input
Python
try:
print('MaximoFN')
except NameError:
print("Ha ocurrido una excepción")
else:
print('Todo OK')
Copied
>_ Output
			
MaximoFN
Todo OK

con la palabra finally se ejecutará un código al final haya ocurrido una excepción o no

	
< > Input
Python
try:
print(variable_no_declarada)
except:
print("Ha ocurrido una excepción")
finally:
print("'try except' finallizado")
Copied
>_ Output
			
Ha ocurrido una excepción
'try except' finallizado

Esto puede resultar útil para cerrar objetos y limpiar recursos

	
< > Input
Python
class Clase:
variable = 'MaximoFN'
objeto = Clase()
try:
print(Clase.mi_variable)
except:
print("Ha ocurrido una excepción")
finally:
del objeto
Copied
>_ Output
			
Ha ocurrido una excepción

12.1. Crear una excepciónlink image 18

Como desarrollador de Python, se puede elegir lanzar una excepción si ocurre una condición.

Para lanzar (o generar) una excepción, hay que usar la palabra clave raise

	
< > Input
Python
def division(numerador, denominador):
if denominador == 0:
raise Exception("El denominador no puede ser 0")
return numerador/denominador
print(division(10, 0))
Copied
>_ Output
			
---------------------------------------------------------------------------Exception Traceback (most recent call last)&lt;ipython-input-16-33fb6066fa78&gt; in &lt;module&gt;
5 return numerador/denominador
6
----&gt; 7 print(division(10, 0))
&lt;ipython-input-16-33fb6066fa78&gt; in division(numerador, denominador)
1 def division(numerador, denominador):
2 if denominador == 0:
----&gt; 3 raise Exception("El denominador no puede ser 0")
4
5 return numerador/denominador
Exception: El denominador no puede ser 0

Se puede definir qué tipo de error generar y el texto que se mostrará al usuario

	
< > Input
Python
def division(numerador, denominador):
if denominador == 0:
raise TypeError("El denominador no puede ser 0")
return numerador/denominador
print(division(10, 0))
Copied
>_ Output
			
---------------------------------------------------------------------------TypeError Traceback (most recent call last)&lt;ipython-input-17-26bfa63ae44c&gt; in &lt;module&gt;
5 return numerador/denominador
6
----&gt; 7 print(division(10, 0))
&lt;ipython-input-17-26bfa63ae44c&gt; in division(numerador, denominador)
1 def division(numerador, denominador):
2 if denominador == 0:
----&gt; 3 raise TypeError("El denominador no puede ser 0")
4
5 return numerador/denominador
TypeError: El denominador no puede ser 0

13. Keywords o palabras reservadaslink image 19

Durante este post en varias ocasiones han aparecido palabras reservadas de Python o keywords, estas son una serie de palabras reservadas por Python

A continuación se muestra una lista de las keywords

	
< > Input
Python
import keyword
keyword.kwlist
Copied
>_ Output
			
['False',
'None',
'True',
'and',
'as',
'assert',
'async',
'await',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
'return',
'try',
'while',
'with',
'yield']

14. El ZEN de Pythonlink image 20

Importando el módulo this podemos leer el zen de Python, es decir, su filosofía o principios

	
< > Input
Python
import this
Copied
>_ Output
			
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Seguir leyendo

Últimos posts -->

¿Has visto estos proyectos?

Gymnasia

Gymnasia Gymnasia
React Native
Expo
TypeScript
FastAPI
Next.js
OpenAI
Anthropic

Aplicación móvil de entrenamiento personal con asistente de IA, biblioteca de ejercicios, seguimiento de rutinas, dieta y medidas corporales

Horeca chatbot

Horeca chatbot Horeca chatbot
Python
LangChain
PostgreSQL
PGVector
React
Kubernetes
Docker
GitHub Actions

Chatbot conversacional para cocineros de hoteles y restaurantes. Un cocinero, jefe de cocina o camaeror de un hotel o restaurante puede hablar con el chatbot para obtener información de recetas y menús. Pero además implementa agentes, con los cuales puede editar o crear nuevas recetas o menús

Naviground

Naviground Naviground
Ver todos los proyectos -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres ver alguna charla?

Últimas charlas -->

¿Quieres mejorar con estos tips?

Últimos tips -->

Usa esto en local

Los espacios de Hugging Face nos permite ejecutar modelos con demos muy sencillas, pero ¿qué pasa si la demo se rompe? O si el usuario la elimina? Por ello he creado contenedores docker con algunos espacios interesantes, para poder usarlos de manera local, pase lo que pase. De hecho, es posible que si pinchas en alún botón de ver proyecto te lleve a un espacio que no funciona.

Flow edit

Flow edit Flow edit

Edita imágenes con este modelo de Flow. Basándose en SD3 o FLUX puedes editar cualquier imagen y generar nuevas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos los contenedores -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

HuggingFace

Dataset de chistes en inglés

Uso: Fine-tuning de modelos de generación de texto humorístico

231K filas 2 columnas 45 MB
Ver en HuggingFace →

opus100

HuggingFace

Dataset con traducciones de inglés a español

Uso: Entrenamiento de modelos de traducción inglés-español

1M filas 2 columnas 210 MB
Ver en HuggingFace →

netflix_titles

HuggingFace

Dataset con películas y series de Netflix

Uso: Análisis de catálogo de Netflix y sistemas de recomendación

8.8K filas 12 columnas 3.5 MB
Ver en HuggingFace →
Ver más datasets -->