Python fundamentals for Data Science
Table of Contents
Referencias#
- Python Syntax - W3Schools
- SoloLearn - Python Courses
- CS50’s Python Course - Harvard
- freeCodeCamp Python Curriculum
- Learn Python in Y Minutes
1. Operaciones con numeros y flotantes#
# Sumamos 1 más 1 y mostramos el resultado
print(1+1) # La salida será 2
# Restamos 1 de 8 y mostramos el resultado
print(8-1) # La salida será 7
# Multiplicamos 10 por 2 y mostramos el resultado
print(10*2) # La salida será 20
# División
# Dividimos 11 entre 4 y mostramos el resultado
print(11/4) # La salida será 2.75 (como número decimal)
# Dividimos 11.0 entre 4.0 y mostramos el resultado
print(11.0/4.0) # La salida también será 2.75 (como número decimal)
# Modulo
# Calculamos el residuo de la división de 7 entre 3 y mostramos el resultado
print(7%3) # La salida será 1
# Exponentes
# En este espresión elevamos 2 a la cuarta potencia y mostramos el resultado
print(2**4) # La salida será 16
# PEMDAS
# realiza la adición antes de la multiplicación, siguiendo la regla de PEMDAS.
print(1 + 3 * 2) # => 7
print((1 + 3) * 2) # => 8
Cual es el resultado de print(( (2 + 8 / 4 ** 2) * (3 - 1) ) % 5) ?
resultado = ( (2 + 8 / 4 ** 2) * (3 - 1) ) % 5
print(resultado) # ¿Qué imprime?
Por si no se acuerdan el acrónimo PEMDAS se usa para recordar el orden de las operaciones aritméticas:
- Primero las operaciones dentro de los paréntesis.
- Luego exponentes o potencias.
- Luego multiplicaciones y divisiones de izquierda a derecha.
- Y por último sumas y restas también de izquierda a derecha.
2. Operaciones con boleanos#
# Realizamos la operación lógica "and" entre True y False y mostramos el resultado
print(True and False) # La salida será False
# En esta operación "and", ambos operandos deben ser True para que el resultado sea True.
# Como uno de los operandos es False, el resultado es False.
# Realizamos la operación lógica "or" entre False y True y mostramos el resultado
print(False or True) # La salida será True
# En esta operación "or", al menos uno de los operandos debe ser True para que el resultado sea True.
# Como uno de los operandos es True, el resultado es True.
Ojo
En Python, las comparaciones entre valores numéricos y valores booleanos pueden ser interesantes debido a que por ejemplo:
# Comparamos si 0 es igual a False y mostramos el resultado
print(0 == False) # La salida será True
# En Python, False se considera igual a 0 en contextos de comparación numérica.
# Comparamos si 1 es igual a True y mostramos el resultado
print(1 == True) # La salida será True
# Al igual que en el caso anterior, True se considera igual a 1 en contextos de comparación numérica.
# Mucho cuidado
print(True + True) # => 2
print(True * 8) # => 8
print(False - 5) # => -5
print(0 == False) # => True
print(2 > True) # => True
print(2 == True) # => False
print(-5 != False) # => True
# Aplicamos la operación lógica "not" a True y mostramos el resultado
print(not True) # La salida será False
# La operación "not" invierte el valor booleano. Como True se invierte a False, la salida es False.
# Aplicamos la operación lógica "not" a False y mostramos el resultado
print(not False) # La salida será True
# De manera similar, la operación "not" invierte el valor booleano. Como False se invierte a True, la salida es True
print(5 == 5.0) # => True (Igualdad)
print(3 != "3") # => True (Desigualdad)
print(10 > 8.5) # => True (Mayor que)
print("a" < "b") # => True (Menor que - orden lexicográfico)
print([1, 2] >= [1]) # => True (Mayor o igual que - compara listas)
print(None <= None) # => True (Menor o igual que - None solo es igual a None)
# [1, 2] >= [1] es True porque:
# Los primeros elementos son iguales (1 == 1).
# La lista izquierda es más larga (tiene un elemento extra: 2).
3. Operaciones con cadenas de caracteres#
# Cadenas
print("This is a string.")
print('This is also a string.')
# La forma que se utiliza para inyectar valores en cadenas
name = "jorge"
age = 33
print(f"{name} is {age} years old.")
# Slices Básicos [start:stop]
cad = "w3resource"
print(cad[:2] + cad[-2:]) # Primeros 2 + últimos 2: 'w3ce'
cad = "w3"
print(cad[:2] + cad[-2:]) # 'w3w3' (solapa cuando len(cad) <= 4)
cad = "w"
print(cad[:2] + cad[-2:]) # 'ww' (Python no da error con índices fuera de rango)
# Slices Complejos [start:stop:step]
cad = "w3resource"
print(cad[2:8:2]) # Desde índice 2 al 8, cada 2 caracteres: 'reo'
print(cad[::-1]) # Invierte la cadena: 'ecruoser3w'
print(cad[5:1:-1]) # Desde 5 al 1 en reversa: 'oser'
Como ocultar una tarjeta de crédito menos los 4 últimos números?
def ocultar_tarjeta(numero):
num_str = str(numero)
return f"{**** **** **** {num_str[-4:]}" # "**** **** **** 5678"
print(ocultar_tarjeta(1234567890125678))
4. Colecciones#
print(type([]))
print(type(()))
print(type({}))
print(type(set()))
# Tipos de estructuras vacías
# 📚 Características de las Listas en Python `[]`
# Mutables
# Se pueden modificar después de su creación:
lista = [1, 2, 3]
lista[0] = 99 # [99, 2, 3]
# Ordenadas
# Conservan el orden de inserción:
[3, 1, 2] == [1, 2, 3] # False
# Heterogéneas
# Acepan múltiples tipos de datos:
mezcla = [1, "Python", True, 3.14, [1, 2]]
# Acceso por índices
# (`[0]`) y negativos (`[-1]`):
lista = [10, 20, 30]
print(lista[-1]) # 30
# Slicing
# Subconjuntos con `[inicio:fin:paso]`:
[1, 2, 3, 4][1:3] # [2, 3]
[1, 2, 3, 4][::2] # [1, 3]
[1, 2, 3, 4][::-1] # [4, 3, 2, 1]
# Anidadas
# Pueden contener otras listas:
matriz = [[1, 2], [3, 4]]
# operaciones de listas
lista = [1, 2, 3]
lista.extend([4, 5]) # [1,2,3,4,5]
lista.insert(1, 99) # [1,99,2,3]
lista.remove(2) # [1,99,3]
lista.reverse() # [3,99,1]
# 📚 Características de las Tuplas en Python `()`
## 📌 Características Principales
# Inmutables
# No se pueden modificar después de su creación:
tupla = (1, 2, 3)
# tupla[0] = 99 # Error: TypeError
# Ordenadas
# Conservan el orden de inserción:
(3, 1, 2) == (1, 2, 3) # False
# Heterogéneas
# Aceptan múltiples tipos de datos:
mezcla = (1, "Python", True, 3.14, [1, 2]) # Sí permite listas internas
# Acceso por índices
# Positivos (`[0]`) y negativos (`[-1]`):
tupla = (10, 20, 30)
print(tupla[-1]) # 30
# Slicing
# Subconjuntos con `[inicio:fin:paso]`:
(1, 2, 3, 4)[1:3] # (2, 3)
(1, 2, 3, 4)[::2] # (1, 3)
(1, 2, 3, 4)[::-1] # (4, 3, 2, 1)
# Anidadas
# Pueden contener otras tuplas:
matriz = ((1, 2), (3, 4))
# Operaciones de listas
# Concatenación
tupla1 = (1, 2)
tupla2 = (3, 4)
print(tupla1 + tupla2) # (1, 2, 3, 4)
# Repetición
print(("a",) * 3) # ('a', 'a', 'a')
# Longitud
print(len((1, 2, 3))) # 3
# Contenido
print(2 in (1, 2, 3)) # True
tupla = (1, 2, 2, 3)
# count() - Cuenta ocurrencias
print(tupla.count(2)) # 2
# index() - Devuelve primera posición
print(tupla.index(3)) # 3
# Desempaquetado
a, b, c = (1, 2, 3)
print(b) # 2
# 📚 Características de los Diccionarios en Python `{}`
## 📌 Características Principales
# Mutables
# Se pueden modificar después de su creación:
# Como también se pueden crear directamente:
dic = {'a': 1, 'b': 2}
dic['a'] = 99 # {'a': 99, 'b': 2}
# No ordenados (hasta Python 3.6)
# A partir de Python 3.7+ mantienen orden de inserción:
{'a': 1, 'b': 2} == {'b': 2, 'a': 1} # False en Python 3.7+
# Claves únicas
# Las claves no se pueden repetir:
dic = {'a': 1, 'a': 2} # {'a': 2} (sobrescribe)
# ejemplo de diccionarios
dic = {'a': 1, 'b': 2}
# Acceso
print(dic['a']) # 1
print(dic.get('c', 'default')) # 'default' (evita KeyError)
# Agregar/Modificar
dic['c'] = 3 # {'a': 1, 'b': 2, 'c': 3}
# Eliminar
del dic['b'] # {'a': 1, 'c': 3}
valor = dic.pop('a') # valor=1, dic={'c': 3}
# metodos importantes
dic = {'a': 1, 'b': 2}
# keys(), values(), items()
print(dic.keys()) # dict_keys(['a', 'b'])
print(dic.values()) # dict_values([1, 2])
print(dic.items()) # dict_items([('a', 1), ('b', 2)])
# 📚 Características de los Conjuntos (Sets) en Python `{}`
## 📌 Características Principales
# Mutables (set) vs Inmutables (frozenset)
mi_set = {1, 2, 3}
mi_frozenset = frozenset([1, 2, 3])
# No ordenados
print({2, 1, 3} == {1, 2, 3}) # True
# Elementos únicos (no duplicados)
print({1, 1, 2}) # {1, 2}
# Hashables como elementos
valido = {1, 'a', (1, 2)}
# invalido = {[1, 2]} # TypeError (listas no son hashables)
a = {1, 2, 3}
b = {3, 4, 5}
# Unión
print(a | b) # {1, 2, 3, 4, 5}
# Intersección
print(a & b) # {3}
# Diferencia
print(a - b) # {1, 2}
# Diferencia simétrica
print(a ^ b) # {1, 2, 4, 5}
# Metodos esenciales
s = {1, 2}
# Añadir elemento
s.add(3) # {1, 2, 3}
# Eliminar
s.remove(2) # {1, 3} (KeyError si no existe)
s.discard(99) # No da error
# Pop (elimina aleatorio)
elem = s.pop()
# Limpiar
s.clear() # set()
5. Control de flujo#
6. Funciones#
7. Alcance de las variables#
# Alcance de Variables
# Definimos una variable global 'x' con el valor 5.
x = 5
# Creamos una función 'set_x' que toma un argumento 'num'.
def set_x(num):
# Dentro de la función, creamos una nueva variable local 'x' con el valor 'num'.
x = num
# Imprimimos el valor de 'x' dentro de la función 'set_x'.
print("Dentro de set_x:", x)
# Creamos una función 'set_global_x' que toma un argumento 'num'.
def set_global_x(num):
# Utilizamos la palabra clave 'global' para indicar que estamos modificando la variable global 'x'.
global x
# Imprimimos el valor de la variable global 'x' antes de cambiarlo.
print("Antes de set_global_x:", x)
# Asignamos el valor 'num' a la variable global 'x'.
x = num
# Imprimimos el nuevo valor de la variable global 'x'.
print("Después de set_global_x:", x)
# Imprimimos el valor de la variable global 'x' antes de llamar a las funciones.
print("Valor de x antes de las funciones:", x)
# Llamamos a las funciones 'set_x' y 'set_global_x' con diferentes valores.
set_x(43) # Esto crea una variable local 'x' con el valor 43 y la imprime.
set_global_x(6) # Esto modifica la variable global 'x' y la imprime.
# Imprimimos el valor de la variable global 'x' después de llamar a las funciones.
print("Valor de x después de las funciones:", x)
Colecciones o estructuras de datos
8. OPP#
from abc import ABC, abstractmethod, ClassVar
# Abstracción: Definir interfaces y ocultar detalles complejos
class Animal(ABC): # Clase abstracta
@abstractmethod
def make_sound(self) -> str:
pass
# Encapsulamiento: Ocultar detalles internos y proveer interfaz controlada
# Herencia de la clase Animal
class Dog(Animal):
"""A class representing a dog with basic attributes and behaviors."""
species: ClassVar[str] = 'mammal'
total_dogs = 0 # Variable de clase para rastrear todos los perros creados
def __init__(self, name: str, age: int) -> None:
if not name:
raise ValueError("Name cannot be empty")
if age <= 0:
raise ValueError("Age must be positive")
# Atributos "protegidos" (por convención con _)
self._name: str = name
self._age: int = age
Dog.total_dogs += 1 # Incrementa el contador al crear una nueva instancia
publico = 1 # Público
_protegido = 2 # Protegido (por convención)
__privado = 3 # "Privado" (name mangling)
@property
def description(self) -> str:
"""Return a formatted string with the dog's name and age."""
return f"{self._name} is {self._age} years old"
def speak(self, sound: str) -> str:
return f"{self._name} says {sound.lower()}"
def have_birthday(self) -> None:
"""Increment the dog's age by 1 year."""
self._age += 1
print(f"Happy birthday {self._name}! Now {self.description}")
@staticmethod
def dog_years_to_human(years: int) -> float:
return years * 4
@classmethod
def from_birth_year(cls, name: str, birth_year: int) -> 'Dog':
current_year = 2023 # Podría obtenerse de datetime.now().year
age = current_year - birth_year
return cls(name, age) # cls se refiere a la clase misma crea una nueva instancia (Dog)
@classmethod
def get_total_dogs(cls) -> int:
"""Método de clase para obtener el total de perros creados."""
return cls.total_dogs
# Métodos para obtener y modificar los atributos privados
def get_name(self):
return self.__name
def get_age(self):
return self.__age
def set_name(self, name):
self.__name = name
def set_age(self, age):
self.__age = age
# polimorfismo se ve mejor cuando tenemos múltiples clases no relacionadas por herencia pero que comparten la misma interfaz.
class Cat(Animal):
def __init__(self, name: str):
self.name = name
def make_sound(self) -> str:
return "Meow!"
# Acceso:
e = Ejemplo()
print(e.publico) # ✅ 1
print(e._protegido) # ⚠️ 2 (accesible pero no recomendado)
# print(e.__privado) # ❌ Error
print(e._Ejemplo__privado) # ⚠️ 3 (acceso forzado - evitar
Que es el ABC
Es una clase especial del módulo abc que permite crear clases abstractas:
- No se puede instanciar directamente: Solo sirve como plantilla.
- Obliga a implementar métodos: Define un “contrato” que las subclases deben cumplir.
9. ERRORES#
# Esto causará un error de sintaxis.
print( 0 / 0 ))
# Cell In[14], line 2
# print( 0 / 0 ))
^
# SyntaxError: unmatched ')'
# Esto causará un error de división por cero, pero la sintaxis será correcta.
print( 0 / 0)
# ---------------------------------------------------------------------------
# ZeroDivisionError Traceback (most recent call last)
# Cell In[15], line 2
# 1 # Esto causará un error de división por cero, pero la sintaxis será correcta.
# ----> 2 print( 0 / 0)
# ZeroDivisionError: division by zero
# Asignamos un valor a la variable x.
x = 10
# Comprobamos si x es mayor que 5.
if x > 5:
# Si x es mayor que 5, levantamos una excepción con un mensaje personalizado.
raise Exception(f'x should not exceed 5. The value of x was: {x}')
# Bloque try-except básico (except se ejecuta si hay errores)
try:
# Código que puede fallar
archivo = open("inexistente.txt")
except Exception as e:
print(f"Ocurrió un error: {e}")
# Bloque try-except con múltiples excepciones
try:
# Código que puede fallar
archivo = open("inexistente.txt")
except FileNotFoundError as e:
print(f"Archivo no encontrado: {e}")
except PermissionError as e:
print(f"Permiso denegado: {e}")
except Exception as e:
print(f"Ocurrió un error: {e}")
# Bloque else (se ejecuta si no hay errores)
try:
# print("Intentando abrir el archivo")
archivo = open("datos.txt", "r") # Modo lectura
contenido = archivo.read()
except Exception as e:
print(f"Ocurrió un error: {e}")
else:
# print("Archivo leído correctamente")
print(f"Contenido: {contenido}")
# Bloque try-except-finally
try:
# Código que puede fallar
archivo = open("datos.txt", "r") # Modo lectura
contenido = archivo.read()
except Exception as e:
print(f"Ocurrió un error: {e}")
else:
# print("Archivo leído correctamente")
print(f"Contenido: {contenido}")
finally:
# Cerrar el archivo, independientemente de si hubo errores o no
archivo.close()