Referencias#

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:

  1. Primero las operaciones dentro de los paréntesis.
  2. Luego exponentes o potencias.
  3. Luego multiplicaciones y divisiones de izquierda a derecha.
  4. 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()