¿Cómo funciona Python?
Python es un lenguaje interpretado lo que significa que tu código es transformado por el intérprete (máquina virtual de Python) a bytecode antes de ser ejecutado por un ordenador con x sistema operativo.
El bytecode
Es un lenguaje de programación de más bajo nivel que puede ser leído por un intérprete.
Aquí un ejemplo de una función pasando a bytecode.
Interprete
Es la máquina virtual, traduce el bytecode a código máquina (ceros y unos).
¿Los lenguajes interpretados son más lentos?
La respuesta se puede resumir en la siguiente frase:
C cuando se debe y Python cuando se puede.
Garbage collector
Recuerda que el garbage collector toma los objetos y variables que no están en uso y los elimina.
¿Qué es la carpeta Pycache?
_pycache _ Es el directorio (carpeta) que contiene el bytecode (el código intermedio) que crea Python para que lo pueda leer la máquina y no tenga que convertirlo de nuevo a bytecode.
¿Cómo organizar las carpetas de tus proyectos?
Paquetes y módulos
Módulo
- Es cualquier archivo de Python.
- Generalmente, contiene código que se puede reutilizar.
Paquete
- Es un conjunto de módulos en una carpeta.
- Siempre posee el archivo
__init__.py
Ejemplo:
Proyecto de exploración espacial:
nave.py
→ Explica el funcionamiento de la nave.
destino.py
→ Calcular las coordenadas del destino.
plataforma.py
→ Permite manipular la plataforma.
lanzamiento.py
→ Cualidades que necesita la nave.
test.py
→ Contiene funciones de prueba.
validacion.py
→Verifica identidad de los pasajeros.
¿Cómo se vería esto en una estructura de carpetas?
README
→ Como trabajar con este proyecto.
.gitignore
→ Ignorar archivos en repositorios GIT
venv
→ Entorno virtual
exploracion_espacial
→ Paquete que contiene el: __init__.py
¿Qué son los tipados?
💻 Los tipados es una clasificación de los lenguajes de programación, tenemos cuatro tipos:
- Estático
- Dinámico
- Débil
- Fuerte
El tipado del lenguaje depende de cómo trata a los tipos de datos.
El tipado estático es el que levanta un error en el tiempo de compilación, ejemplo en JAVA:
String str = "Hello" // Variable tipo String
str = 5
// ERROR: no se puede convertir un tipo de dato en otro de esta forma.
El tipado dinámico levantan el error en tiempo de ejecución, ejemplo en Python:
str = "Hello" # Variable tipo String
str = 5 # La variable ahora es de tipo Entero, no hay error
## TIPADO FUERTE
x = 1
y = "2"
z = x + y # ERROR: no podemos hacer estas operaciones con tipos de datos distintos entre sí
El tipado débil es el que hace un cambio en un tipo de dato para poder operar con él, como lo hace JavaScript y PHP.
🐍 Python es un lenguaje de tipado 👾 Dinámico y 💪 Fuerte.
Tipado estático en Python (Static Typing)
Asignar tipos a las variables de Python:
Asignar tipos en funciones:
Trabajando con estructuras de datos:
Trabajar con tipos
Importar de la librería typing
las clases Dict
y List
from typing import Dict, List
Definir una lista de enteros:
positives: List[int] = [1,2,3]
Lista de diccionarios con llaves y valores
countries: List[Dict[str, str]]
Las ventajas de utilizar tipado estático en Python:
- Nos aporta claridad del código.
- Nos da calidad a lo que estamos programando.
- Nuestro código va a ser más entendible a otros programadores si trabajamos con tipos.
- Nos va a devolver los errores antes del que programa se ejecute.
Scope: alcance de las variables
- El Scope es el alcance que tienen las variables.
- Depende de donde declares o inicialices una variable para saber si tienes acceso.
Local Scope
Es la región que corresponde el ámbito de una función, donde podremos tener una o más variables, las variables van a ser accesibles únicamente en esta región y no serán visibles para otras regiones
Global Scope
Al escribir una o más variables en esta región, estas podrán ser accesibles desde cualquier parte del código.
Closures
Es una forma de acceder a variables de otros Scopes a través de una nested function. Se retorna la nested function y esta recuerda el valor que imprime, aunque a la hora de ejecutarla no este dentro de su alcance.
Nested Functions (Funciones anidadas)
Funciones creadas dentro de otra función:
def main():
a = 1
def nested():
print(a)
return nested
my_func = main()
my_func()
Reglas para encontrar un Closure
- Debemos tener una nested function.
- La nested function debe referenciar un valor de un scope superior.
- La función que envuelve a la nested function debe retornarla también.
Decoradores
Un decorador es una función que recibe como parámetro otra función, le añade cosas y retorna una función diferente.
Tienen la misma estructura que los Closures
, pero en vez de variables lo que se envía es una función.
Ejemplo:
def decorador(func):
def envoltura():
print("Esto se añade a mi función original.")
func()
return envoltura
def saludo():
print("¡Hola!")
saludo()
# Salida:
# ¡Hola!
saludo = decorador(saludo) # Se guarda la función decorada en la variable saludo
saludo() # La función saludo está ahora decorada
# Salida:
# Esto se añade a mi función original.
# ¡Hola!
Se puede hacer de manera más sencilla, con azúcar sintáctica (sugar syntax): Cuando tenemos un código que está embellecido para que nosotros lo veamos de una manera más estática, ayudando a entender de manera más sencilla el código.
De esta manera, tenemos el código anterior:
def decorador(func):
def envoltura():
print("Esto se añade a mi función original.")
func()
return envoltura
def saludo():
print("¡Hola!")
saludo = decorador(saludo) # Se guarda la función decorada en la variable saludo (se decora)
saludo() # La función saludo está ahora decorada
def decorador(func):
def envoltura():
print("Esto se añade a mi función original.")
func()
return envoltura
# De esta manera se decora la función saludo (equivale a saludo = decorador(saludo) de la última línea, quedando ahora en la línea inmediata superior ):
@decorador
def saludo():
print("¡Hola!")
saludo() # La función saludo está ahora decorada
Esto permite ahorrar código al implementar características (decoradores) comunes a diferentes funciones:
def decorator_upper(func): # Función decoradora
def wrapper(text): # Función anidada
return func(text).upper() # Operación que realiza el decorado a la función (func), inserta el texto a la función original. Convierte todo a mayúsculas.
return wrapper # Devuelve wapper como indica la regla de los Clousures
@decorator_upper # Decora la función message
def message(name):
return f'{name}, recibiste un mensaje' # Esto es lo que realiza la función message, previo a ser decorada.
@decorator_upper # Decora la función warning
def warning(name):
return f'Usa solo mayúsculas {name}' # Esto es lo que realiza la función warning, previo a ser decorada.
print(message("Cesar")) # Output: CESAR, RECIBISTE UN MENSAJE
print(warning("Cesar")) # Output: USA SOLO MAYÚSCULAS CESAR
Iteradores
Antes de entender qué son los iteradores
, primero debemos entender a los iterables.
- Son todos aquellos objetos que podemos recorrer en un ciclo. - Son aquellas estructuras de datos divisibles en elementos únicos que yo puedo recorrer en un ciclo.
Pero en Python las cosas no son así. Los iterables se convierten en iteradores
.
Ejemplo:
# Creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# Iterando un iterador
print(next(my_iter))
# Cuando no quedan datos, la excepción StopIteration es elevada
# Creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# Iterando un iterador
while True: #ciclo infinito
try:
element = next(my_iter)
print(element)
except StopIteration:
break
Momento impactante: El ciclo “for
” dentro de Python, no existe. Es un while
con StopIteration
. 🤯🤯🤯
my_list = [1,2,3,4,5]
for element in my_list:
print(element)
evenNumbers.py
class EvenNumbers:
"""Clase que implementa un iterador de todos los números pares,
o los números pares hasta un máximo
"""
#* Constructor de la clase
def __init__(self, max = None): #self hace referencia al objeto futuro que voy a crear con esta clase
self.max = max
# Método para tener elementos o atributos que voy a necesitar para que el iterador funcione
def __iter__(self):
self.num = 0 #Primer número par
#* Convertir un iterable en un iterador
return self
# Método para tener la función "next" de Python
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
Ventajas de usar iteradores:
- Nos ahorra recursos.
- Ocupan poca memoria.
Generadores
Sugar syntax de los iteradores. Los generadores son funciones que guardan un estado. Es un iterador escrito de forma más simple.
def my_gen():
"""un ejemplo de generadores"""
print('Hello world!')
n = 0
yield n # es exactamente lo mismo que return pero detiene la función, cuando se vuelva a llamar a la función, seguirá desde donde se quedó
print('Hello heaven!')
n = 1
yield n
print('Hello hell!')
n = 2
yield n
a = my_gen()
print(next(a)) # Hello world!
print(next(a)) # Hello heaven!
print(next(a)) # Hello hell!
print(next(a)) StopIteration
Ahora veremos un generator expression (es como list comprehension pero mucho mejor, porque podemos manejar mucha cantidad de información sin tener problemas de rendimiento):
#Generator expression
my_list = [0,1,4,7,9,10]
my_second_list = [x*2 for x in my_list] #List comprehension
my_second_gen = ()x*2 for x in my_list]) #Generator expression
Sets
Un set es una colección desordenada de elementos únicos e inmutables.
¿Cómo se crean los sets?
my_set = {1, 2, 3, 4, 5}
print("my_set =", my_set)
my_set2 = {"Hola", 2.4, False, True}
print("my_set2 =", my_set2)
my_set3 = {3,3,2}
print("my_set3 =", my_set3)
my_set4 = {[1,2,3], [4,5,6],4}
print("my_set4 =", my_set4)
## Este último da error porque una lista es un elemento mutable
Una llave sin los dos puntos crea un set
Se puede crear sets vacíos…
empty_set = {}
print(type(empty_set)) #<class 'dict'>
empty_set = set()
print(type(empty_set)) # <class 'set'>
Datos a tener en cuenta:
- Python trata las llaves como un diccionario
- Se usa la función set() para indicar que es un set
Casting con set
Convertir un set a otra estructura de datos, o una estructura de datos a un set.
my_list = [1,1,2,3,45,324]
my_set = set(my_list)
print(my_set)
my_tulpe = ("hola", "hola", "hola", 1)
my_set2 = set(my_tulpe)
print(my_set2)
# {1, 2, 3, 324, 45}
# {1, 'hola'}
Datos a tener en cuenta:
- Para transformar una lista y una tupla. solo tenemos que usar el set() sobre la variable
- El set() elimina los elementos que se repiten.
Añadir elementos a un set
my_set = {1,2,3}
print(my_set)
#añadir un elemento
my_set.add(4)
print(my_set)
#añadir múltiples elementos
my_set.update([1,2,5])
#añadir múltiples elementos
my_set.update([1,7,2], {6,8})
print(my_set)
# {1, 2, 3}
# {1, 2, 3, 4}
# {1, 2, 3, 4, 5, 6, 7, 8}
Datos a tener en cuenta:
acá podemos apreciar de que hay métodos que se pueden combinar con los set, por ejemplo .add() y .update(). el .add para agregar un elemento y el update para agregar múltiples elementos
Borrar elementos de un set
my_set = {1,2,3,4,5,6,7}
print(my_set)
#Borrar un elemento existente
my_set.discard(1)
my_set.discard(2)
print(my_set)
#borrar un elemento inexistene
my_set.discard(10)
my_set.remove(12)
print(my_set)
# {1, 2, 3, 4, 5, 6, 7}
# {3, 4, 5, 6, 7}
# Traceback (most recent call last):
# File "python.py", line 28, in <module>
# my_set.remove(12)
# KeyError: 12
Se usan los métodos discard y remove
Si el elemento no existe con remove, lanza un error de tipo KeyError. Remove, es más exigene.
Para eliminar elementos aleatorios se usa el pop()
y para eliminar todos los elementos del set se usa .clear()
Operaciones con sets
Métodos Set
from platform import system
from os import system as console_command
# Utility
def clean_screen() -> None:
"""This function is responsible for cleaning the screen."""
if system() == 'Windows': console_command('cls')
else: console_command('clear')
def sets() -> None:
"""Multiple Operations with sets"""
my_set1 = {'🍎', '🍊', '🍇', '🍓', '🍈'}
my_set2 = {'🍉', '🍊', '🍒', '🍓', '🍋'}
print(" → Set 1:", my_set1)
print(" → Set 2:", my_set2)
print('')
# Union
my_set3 = my_set1 | my_set2
print(" Union :", my_set3)
# Intersection
my_set4 = my_set1 & my_set2
print("\n Intersection :", my_set4)
# Difference
my_set5 = my_set1 - my_set2
print("\n Difference set1 - set2 :", my_set5)
my_set6 = my_set2 - my_set1
print("\n Difference set2 - set1 :", my_set6)
# Symmetric Difference
my_set7 = my_set1 ^ my_set2
print("\n Symmetric Difference :", my_set7)
if __name__ == '__main__':
clean_screen()
print("*** O P E R A T I O N S W I T H S E T S ***\n")
sets()
Manejo de fechas
datetime
es un módulo de manejo de fechas aquì un ejemplo de su uso:
import datetime
my_time = datetime.datetime.now() # hora local de mi PC u hora universal
my_date = datetime.date.today() # fecha actual
my_day = datetime.date.today()
print(my_time)
print(my_date)
print(f'Year: {my_day.year}')
print(f'Month: {my_day.month}')
print(f'Day: {my_day.day}')
Tabla de códigos de formato para fechas y horas(los más importantes):
Formato | Código |
---|---|
Año | %Y |
Mes | %m |
Día | %d |
Hora | %H |
Minutos | %M |
Segundos | %S |
from datetime import datetime
my_datetime = datetime.now()
print(my_datetime)
latam = my_datetime.strftime('%d/%m/%Y')
print(f'Formato LATAM: {latam}')
usa = my_datetime.strftime('%m/%d/%Y')
print(f'Formato USA: {usa}')
random_format = my_datetime.strftime('año %Y mes %m día %d')
print(f'Formato random: {random_format}')
formato_utc = datetime.utcnow()
print(f'Formato UTC: {formato_utc}')
Este código importa la clase datetime del módulo datetime, que proporciona diversas funciones para trabajar con fechas y horas.
La primera línea crea un objeto datetime que representa la fecha y hora actual. Luego, se imprime en pantalla utilizando la función print()
.
La siguiente línea utiliza el método strftime()
para dar formato a la fecha y hora actual en un formato específico. El método strftime()
toma una cadena de formato como argumento, que indica cómo se deben mostrar los distintos componentes de la fecha y hora (día, mes, año, etc.). En este caso, el formato especificado es '%d/%m/%Y'
, que indica que se deben mostrar el día, mes y año en ese orden, separados por barras.
La siguiente línea hace lo mismo, pero con un formato distinto: '%m/%d/%Y'
, que indica que se deben mostrar el mes, día y año en ese orden, separados por barras.
La línea siguiente también utiliza el método strftime()
, pero con un formato más personalizado: 'año %Y mes %m día %d'
, que muestra el año, mes y día en ese orden, con las palabras "año", "mes" y "día" incluidas en la cadena de formato.
Por último, se crea un nuevo objeto datetime que representa la fecha y hora actual en el formato UTC (Coordinated Universal Time, o Tiempo Universal Coordinado), que es una referencia de tiempo uniforme utilizada a nivel internacional. Luego, se imprime en pantalla utilizando la función print()
.
¡Gracias por leer este post!😊
Si te ha parecido útil o interesante, puedes darle un like 💙 para motivarme a seguir compartiendo contenido así. Si tienes la oportunidad y quieres apoyar mi trabajo, puedes hacerlo a través de un pequeño donativo 💸 ¡Un café virtual sería un gran detalle! ☕ Puedes hacerlo a través de Ko-fi.
Además, si te gustaría seguir mis actualizaciones y contenido en redes sociales, puedes encontrarme en Twitter y YouTube como "GeoannyCode" 📱💻 Espero verte por allí! 😊 ¡Gracias por tu apoyo! ❤️"
Top comments (1)
buen artículo! No sabía lo del for, que locura!