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 objetos
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
InputPythonclass Clase:variable = 'MaximoFN'Copied
Una vez creada la clase, se puede crear un objeto de dicha clase
InputPythonobjeto = Clase()Clase.variableCopied
'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
InputPythonclass Persona:def __init__(self, nombre, edad):self.nombre = nombreself.edad = edadobjeto_persona = Persona("Miguel", 36)print(objeto_persona.nombre)print(objeto_persona.edad)Copied
Miguel36
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
InputPythonclass Persona:def __init__(self, nombre, edad):self.nombre = nombreself.edad = edaddef 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
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
InputPythonclass Persona:def __init__(yo_mismo, nombre, edad):yo_mismo.nombre = nombreyo_mismo.edad = edaddef 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
Hola mi nombre es Miguel y tengo 36 años
Se pueden modificar las variables de los objetos
InputPythonobjeto_persona.nombre = 'Marta'objeto_persona.saludar()Copied
Hola mi nombre es Marta y tengo 36 años
Incluso eliminarlas
InputPythondel objeto_persona.nombreCopied
También se puede eliminar el objeto entero
InputPythondel objeto_personaCopied
Si, por ejemplo, queremos hacer la estructura de la clase, pero no queremos, de momento, codificar el interior, podemos usar pass
InputPythonclass Persona:passobjeto_persona = Persona()Copied
7.1. Herencia
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
InputPythonclass Persona:def __init__(self, nombre, apellido):self.nombre = nombreself.apellido = apellidodef imprimir_nombre(self):print(f'Me llamo {self.nombre} {self.apellido}')objeto_padre = Persona("Laura", "Perez")objeto_padre.imprimir_nombre()Copied
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
InputPythonclass Estudiante(Persona):passCopied
Y al momento de crear el objeto de la clase hija, se le pasan los parámetros que la clase padre necesita
InputPythonobjeto_hijo = Estudiante("Mariano", "Sanz")objeto_hijo.imprimir_nombre()Copied
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.
InputPythonclass Estudiante(Persona):def __init__(self, nombre, apellido):Persona.__init__(self, nombre, apellido)objeto_hijo = Estudiante("Mariano", "Sanz")objeto_hijo.imprimir_nombre()Copied
Me llamo Mariano Sanz
Otra forma es mediante super(), en este caso no hace falta pasarle la variable self
InputPythonclass Estudiante(Persona):def __init__(self, nombre, apellido):super().__init__(nombre, apellido)objeto_hijo = Estudiante("Mariano", "Sanz")objeto_hijo.imprimir_nombre()Copied
Me llamo Mariano Sanz
Al modificar las funciones se puede agregar código nuevo
InputPythonclass Estudiante(Persona):def __init__(self, nombre, apellido, curso):Persona.__init__(self, nombre, apellido)self.curso = cursodef 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
Me llamo Mariano SanzEstoy en el curso número 4
Por último, se pueden agregar nuevos métodos
InputPythonclass Estudiante(Persona):def __init__(self, nombre, apellido, curso):Persona.__init__(self, nombre, apellido)self.curso = cursodef 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
Me llamo Mariano SanzEstoy en el curso número 4Soy un estudiante del curso número 4
7.2. Sobrecarga de operadores
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
InputPythonclass Vector:def __init__(self, x, y):self.x = xself.y = ydef __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
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óndivmod().__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ónabs().__invert__(self): sobrecarga el operador de inversión (~).__complex__(self): sobrecarga la funcióncomplex().__int__(self): sobrecarga la funciónint().__float__(self): sobrecarga la funciónfloat().
7.3. Iteradores personalizados
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__
InputPythonclass 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)) # 10print(iterator[0]) # 0print(iterator[1]) # 1Copied
1001
Ahora podemos iterar con el objeto de nuestra clase con bucles for, por ejemplo
InputPythonfor i in iterator:print(i, end=" ") # 0 1 2 3 4 5 6 7 8 9Copied
0 1 2 3 4 5 6 7 8 9
7.4. Llamada a objetos como funciones
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
InputPythonclass potencia:def __init__(self, base):self.base = basedef __call__(self, potencia):return self.base ** potenciapotencia_cuadrado = potencia(2)print(potencia_cuadrado(3)) # 8Copied
8
7.5. Atributos y funciones privados
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
InputPythonclass Privados:def __init__(self):self.publico = "Soy público"self.__privado = "Soy privado"def getPrivado(self):return self.__privadodef setPrivado(self, valor):self.__privado = valordef __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
Acceso al atributo publico: Soy públicoAcceso al atributo privado: No se puede acceder al atributo privadoAcceso al atributo privado mediante el accesor: Soy privadoLlamada a la función privada: No se puede llamar a la función privadaLlamada a la función pública: Soy una función privada
8. Iteradores
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:
InputPythontupla = ("manzana", "plátano", "cereza")iterable = iter(tupla)print(next(iterable))print(next(iterable))print(next(iterable))Copied
manzanaplátanocereza
InputPythonstring = "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
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.
InputPythontupla = ("manzana", "plátano", "cereza")for x in tupla:print(x)Copied
manzanaplátanocereza
InputPythonstring = "plátano"for x in string:print(x, end=' ')Copied
p l á t a n o
8.1. Crear un objeto iterador
Para crear un objeto/clase como iterador, hay que implementar los métodos __iter__() y __next__().
InputPythonclass Numeros:def __iter__(self):self.a = 1return selfdef __next__(self):x = self.aself.a += 1return xobjeto_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
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:
InputPythonclass Numeros:def __iter__(self):self.a = 1return selfdef __next__(self):if self.a <= 20:x = self.aself.a += 1return xelse:raise StopIterationobjeto_iterador = Numeros()iterador = iter(objeto_iterador)for x in iterador:print(x, end=' ')Copied
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 valor
Podemos iterar por un objeto iterable obteniendo en cada iteración su índice y su valor mediante el método enumerate()
InputPythonstring = "MaximoFN"for index, valor in enumerate(string):print(f"En la posición {index}, está el caracter {valor}")Copied
En la posición 0, está el caracter MEn la posición 1, está el caracter aEn la posición 2, está el caracter xEn la posición 3, está el caracter iEn la posición 4, está el caracter mEn la posición 5, está el caracter oEn la posición 6, está el caracter FEn la posición 7, está el caracter N
8.3. Iterar simultáneamente sobre dos objetos iterables
Si tenemos dos objetos iterables, de la misma longitud, podemos iterar por los dos a la vez mediante el método zip()
InputPythonstring1 = '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
En el primer string hay M, en el segundo string hay PEn el primer string hay a, en el segundo string hay yEn el primer string hay x, en el segundo string hay tEn el primer string hay i, en el segundo string hay hEn el primer string hay m, en el segundo string hay oEn el primer string hay o, en el segundo string hay nEn el primer string hay F, en el segundo string hay PEn el primer string hay N, en el segundo string hay oEn el primer string hay _, en el segundo string hay sEn el primer string hay _, en el segundo string hay t
9. Alcance de variables
Una variable solo está disponible dentro de la región en la que se crea. A esto se le llama *alcance*
9.1. Alcance local
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.
InputPythondef funcion():x = 300print(x)funcion()Copied
300
La variable x no está disponible fuera de la función, pero está disponible para cualquier función dentro de ella
InputPythondef funcion():x = 300def funcion_interna():print(x)funcion_interna()funcion()Copied
300
9.2. Alcance global
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.
InputPythonx = 300def funcion():print(f'Ámbito local: {x}')funcion()print(f'Ámbito global: {x}')Copied
Á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
InputPythonx = 300def funcion():x = 200print(f'Variable local: {x}')funcion()print(f'Variable global: {x}')Copied
Variable local: 200Variable 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.
InputPythondef funcion():global xx = 300funcion()print(f'Variable global: {x}')Copied
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.
InputPythonx = 300def funcion():global xx = 200funcion()print(f'Variable global: {x}')Copied
Variable global: 200
10. Módulos
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*)
InputPython!pwdCopied
/home/wallabot/Documentos/web/portafolio/posts
Vamos a crear una carpeta para crear nuestros modulos con el comando mkdir (make directory)
InputPython!mkdir introduccion_pythonCopied
A continuación veamos qué archivos hay en nuestra carpeta. Esto lo haremos mediante el comando ls (*list*)
InputPython!ls introduccion_pythonCopied
Vemos que está vacía, creamos un nuevo archivo .py en el que vamos a crear nuestro módulo
InputPython%%writefile introduccion_python/modulo1.pydef funcion_del_modulo(nombre):print("Hola, " + nombre)Copied
Writing introduccion_python/modulo1.py
Volvemos a ver qué archivos hay en nuestra carpeta
InputPython!ls introduccion_pythonCopied
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
InputPythonimport introduccion_python.modulo1introduccion_python.modulo1.funcion_del_modulo('MaximoFN')Copied
Hola, MaximoFN
Si queremos que dentro de nuestro código, el módulo tenga un nombre determinado, podemos usar la palabra as
InputPythonimport introduccion_python.modulo1 as mod1mod1.funcion_del_modulo('MaximoFN')Copied
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
InputPython%%writefile introduccion_python/modulo2.pydef 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
Writing introduccion_python/modulo2.py
InputPythonfrom introduccion_python.modulo2 import funcion2_del_modulofuncion2_del_modulo('MaximoFN')Copied
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
InputPythonimport platformx = platform.system()xCopied
'Linux'
10.1. Entry points: archivos como módulos y no como scripts
Vamos ahora a crear un archivo llamado módulo3.py
InputPython%%writefile introduccion_python/modulo3.pyprint("Hola desde modulo3")def funcion_del_modulo():return "Hola desde la función del modulo3"Copied
Overwriting introduccion_python/modulo3.py
Si ahora importamos modulo3.py para usar la función funcion_del_modulo veamos qué ocurre
InputPythonimport introduccion_python.modulo3 as mod3print(mod3.funcion_del_modulo())Copied
Hola desde modulo3Hola 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?
InputPython!python introduccion_python/modulo3.pyCopied
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
InputPython%%writefile introduccion_python/modulo3.pyprint("Hola desde modulo3")def funcion_del_modulo():return "Hola desde la función del modulo3"if __name__ == "__main__":funcion_del_modulo()Copied
Overwriting introduccion_python/modulo3.py
Si ahora llamo a main.py desde otro módulo, ya no se ejecutará el print
InputPythonimport introduccion_python.modulo3 as mod3print(mod3.funcion_del_modulo())Copied
Hola desde la función del modulo3
Y si lo ejecuto como un script independiente, se ejecutará la función función_del_modulo
InputPython!python introduccion_python/modulo3.pyCopied
Hola desde modulo3
11. Paquetes
En Python podemos crearnos nuestros propios paquetes, para ello creamos una carpeta con el nombre del paquete
InputPython!mkdir mi_paquete_de_pythonCopied
Creamos ahora dos archivos dentro
InputPython!touch mi_paquete_de_python/modulo1.py mi_paquete_de_python/modulo2.pyCopied
Y escribimos en ellos
InputPython%%writefile mi_paquete_de_python/modulo1.pydef 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
Overwriting mi_paquete_de_python/modulo1.py
InputPython%%writefile mi_paquete_de_python/modulo2.pydef 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
Overwriting mi_paquete_de_python/modulo2.py
Ahora podemos llamar a las funciones de nuestro paquete
InputPythonfrom mi_paquete_de_python import modulo1 as mod1from mi_paquete_de_python import modulo2 as mod2mod1.funcion1()mod1.funcion2()mod2.funcion1()mod2.funcion2()Copied
Hola desde la función 1 del módulo 1Hola desde la función 2 del módulo 1Hola desde la función 1 del módulo 2Hola 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
InputPython!touch mi_paquete_de_python/__init__.pyCopied
InputPython%%writefile mi_paquete_de_python/__init__.pyimport modulo1import modulo2Copied
Overwriting mi_paquete_de_python/__init__.py
Ahora podemos solamente importar nuestro paquete, que ya internamente se han importado todos los módulos
InputPythonimport mi_paquete_de_python as mi_paquetemi_paquete.modulo1.funcion1()mi_paquete.modulo1.funcion2()mi_paquete.modulo2.funcion1()mi_paquete.modulo2.funcion2()Copied
Hola desde la función 1 del módulo 1Hola desde la función 2 del módulo 1Hola desde la función 1 del módulo 2Hola desde la función 2 del módulo 2
De esta manera solo tenemos que hacer un import
12. Try... except
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
InputPythontry:print(variable_no_declarada)except:print("Ha ocurrido una excepción")Copied
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
InputPythontry:print(variable_no_declarada)except NameError:print("La variable 'variable_no_declarada' no está definida")except:print("Algo inesperado ha ocurrido")Copied
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
InputPythontry:print('MaximoFN')except NameError:print("Ha ocurrido una excepción")else:print('Todo OK')Copied
MaximoFNTodo OK
con la palabra finally se ejecutará un código al final haya ocurrido una excepción o no
InputPythontry:print(variable_no_declarada)except:print("Ha ocurrido una excepción")finally:print("'try except' finallizado")Copied
Ha ocurrido una excepción'try except' finallizado
Esto puede resultar útil para cerrar objetos y limpiar recursos
InputPythonclass Clase:variable = 'MaximoFN'objeto = Clase()try:print(Clase.mi_variable)except:print("Ha ocurrido una excepción")finally:del objetoCopied
Ha ocurrido una excepción
12.1. Crear una excepción
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
InputPythondef division(numerador, denominador):if denominador == 0:raise Exception("El denominador no puede ser 0")return numerador/denominadorprint(division(10, 0))Copied
---------------------------------------------------------------------------Exception Traceback (most recent call last)<ipython-input-16-33fb6066fa78> in <module>5 return numerador/denominador6----> 7 print(division(10, 0))<ipython-input-16-33fb6066fa78> in division(numerador, denominador)1 def division(numerador, denominador):2 if denominador == 0:----> 3 raise Exception("El denominador no puede ser 0")45 return numerador/denominadorException: El denominador no puede ser 0
Se puede definir qué tipo de error generar y el texto que se mostrará al usuario
InputPythondef division(numerador, denominador):if denominador == 0:raise TypeError("El denominador no puede ser 0")return numerador/denominadorprint(division(10, 0))Copied
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-17-26bfa63ae44c> in <module>5 return numerador/denominador6----> 7 print(division(10, 0))<ipython-input-17-26bfa63ae44c> in division(numerador, denominador)1 def division(numerador, denominador):2 if denominador == 0:----> 3 raise TypeError("El denominador no puede ser 0")45 return numerador/denominadorTypeError: El denominador no puede ser 0
13. Keywords o palabras reservadas
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
InputPythonimport keywordkeyword.kwlistCopied
['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 Python
Importando el módulo this podemos leer el zen de Python, es decir, su filosofía o principios
InputPythonimport thisCopied
The Zen of Python, by Tim PetersBeautiful 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!