Clases y objetos de Python: tutorial de programación orientada a objetos con ejemplos reales

  1. Inicio
  2. Blog
  3. Desarrollo de software

Desarrollo de software

Clases y objetos de Python: Tutorial de programación orientada a objetos con ejemplos reales

Aprenda Python orientado a objetos construyendo algo real. Cree clases, comprenda self y __init__, comparta comportamientos con herencia, proteja datos con propiedades y sepa cuándo una clase es la herramienta incorrecta.

10 min de lectura
Clases y objetos de Python: tutorial de POO con ejemplos reales

Puntos clave

  • Una clase es un plano y un objeto es algo construido a partir de él.
  • __init__ configura cada nuevo objeto y self hace referencia a ese objeto.
  • Los atributos establecidos en la clase se comparten. Los atributos establecidos en self pertenecen a un objeto.
  • Utilice @dataclass para clases que contienen datos y prefiera funciones simples cuando no haya un estado que conservar.

A medida que un script crece, terminas pasando el mismo grupo de variables entre funciones y resulta difícil saber qué datos pertenecen a qué lógica. Las clases y objetos de Python resuelven esto agrupando datos y comportamiento en una unidad.

En este tutorial, creamos una pequeña cuenta bancaria paso a paso y agregamos cada idea de programación orientada a objetos solo cuando resuelve un problema. Ejecutamos todos los ejemplos en Python 3.13 y el resultado que se muestra proviene de esa ejecución. Si eres nuevo en el idioma, lee primero nuestro tutorial de Python para principiantes.

¿Qué son las clases y los objetos?

Una clase describe qué es algo y qué puede hacer. Un objeto, también llamado instancia, es uno específico creado a partir de esa descripción. “Cuenta” es una clase, mientras que la cuenta de Asha y la cuenta de Ben son dos objetos.

Término Significado Ejemplo
clase el plano cuenta
Objeto o instancia Una cosa hecha de eso a = Cuenta("Asha")
Atributo Datos sobre el objeto a.balance
Método Una función en la clase. a.deposit(50)

Has estado usando objetos todo el tiempo. En Python, las cadenas, listas e incluso funciones son objetos, por eso puedes escribir "hello".upper().

tu primera clase

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("amount must be positive")
        self.balance += amount
        return self.balance

a = Account("Asha", 100)
b = Account("Ben")

a.deposit(50)
print(a.balance, b.balance)

# 150 0

__init__ se ejecuta automáticamente cada vez que crea un objeto y establece el estado inicial. Depositar en a no tocó b, porque cada objeto tiene sus propios datos. Tenga en cuenta que el método también protege el saldo de un valor incorrecto. Nuestra guía para el manejo de excepciones de Python explica raise con más profundidad.

¿Qué es uno mismo?

self es simplemente el objeto en el que está trabajando un método. Cuando escribes a.deposit(50), Python llama efectivamente a Account.deposit(a, 50), pasando el objeto como primer argumento. Así es como una definición de método puede servir a cada objeto.

El nombre self es una convención fuerte más que una palabra clave, pero utilícela siempre. Olvidarlo en la definición de un método es el error más común de los principiantes y produce un mensaje confuso sobre la cantidad de argumentos.

Atributos de clase versus atributos de instancia

Todos los objetos comparten un atributo establecido directamente en el cuerpo de la clase. Un conjunto en self pertenece únicamente a ese objeto. Este ejemplo muestra cómo se comportan las búsquedas:

class Account:
    interest_rate = 0.04    # class attribute

    def __init__(self, owner, balance=0):
        self.owner = owner  # instance attribute
        self.balance = balance

a = Account("Asha", 100)
b = Account("Ben")
print(a.interest_rate, b.interest_rate)   # 0.04 0.04

Account.interest_rate = 0.05
print(a.interest_rate, b.interest_rate)   # 0.05 0.05

a.interest_rate = 0.09
print(a.interest_rate, b.interest_rate, Account.interest_rate)
# 0.09 0.05 0.05

Esa última línea sorprende a la gente. La asignación a través de a no cambió el valor compartido. Creó un nuevo atributo de instancia en a que oculta el de clase. Python mira primero el objeto y luego la clase.

Métodos especiales (dunder)

Los métodos con guiones bajos dobles permiten que sus objetos funcionen con las funciones integradas de Python. Sin ellos, imprimir una cuenta muestra una dirección de memoria inútil. Agregar dos le da una forma legible:

    def __str__(self):
        return f"{self.owner}: {self.balance}"

    def __repr__(self):
        return f"Account({self.owner!r}, {self.balance})"

print(a)        # Asha: 150
print([a, b])   # [Account('Asha', 150), Account('Ben', 0)]
Método Provocado por
__init__ Creando un objeto
__str__ print(obj), str(obj)
__repr__ Depurarlo o mostrarlo en una lista
__eq__ a == b
__len__ len(obj)
__add__ a+b

herencia

La herencia permite que una nueva clase reutilice una existente y cambie sólo lo que difiere. Aquí, Savings es un Account con una configuración adicional:

class Savings(Account):
    def __init__(self, owner, balance=0, limit=3):
        super().__init__(owner, balance)
        self.limit = limit

    def __str__(self):
        return f"{super().__str__()} (savings)"

s = Savings("Chitra", 500)
s.deposit(100)
print(s, isinstance(s, Account), s.limit)

# Chitra: 600 (savings) True 3

super() llama a la versión principal, por lo que la lógica de configuración no se repite. deposit se heredó tal como estaba y __str__ se anuló para agregar una etiqueta. Utilice la herencia únicamente para una relación real “es un”. Si una clase simplemente necesita algo, como un automóvil que necesita un motor, dale ese objeto como atributo. Esto se conoce como composición y suele ser más flexible que las cadenas de herencia profunda.

polimorfismo

El polimorfismo significa que diferentes objetos pueden responder a la misma llamada a un método a su manera. El código de llamada no necesita saber el tipo exacto:

class Square:
    def __init__(self, side):
        self.side = side
    def area(self):
        return self.side ** 2

class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return round(3.14159 * self.radius ** 2, 2)

for shape in [Square(3), Circle(2)]:
    print(type(shape).__name__, shape.area())

# Square 9
# Circle 12.57

Estas dos clases ni siquiera comparten un padre. A Python solo le importa que el objeto tenga un método area, un enfoque conocido como tipificación pato. Agregar un Triangle más tarde no necesitaría cambios en el bucle.

Encapsulación y propiedades.

Python no tiene atributos verdaderamente privados y, en cambio, se basa en convenciones. Un solo guión bajo, como en _price, les dice a otros desarrolladores “esto es interno, no lo toques”. Para verificar los valores cuando están configurados, use una propiedad, que parece un atributo simple desde el exterior:

class Product:
    def __init__(self, price):
        self.price = price

    @property
    def price(self):
        return self._price

    @price.setter
    def price(self, value):
        if value < 0:
            raise ValueError("price cannot be negative")
        self._price = value

p = Product(100)
p.price = 150
print(p.price)      # 150
p.price = -5        # ValueError: price cannot be negative

Esto significa que puede comenzar con un atributo simple y agregar validación más adelante sin cambiar ningún código que use la clase. Por lo tanto, no escriba los métodos get_price() y set_price() por costumbre, como podría hacerlo en Java. La sintaxis @ aquí es un decorador, que explicamos en Explicación de los decoradores de Python.

Métodos de clase y métodos estáticos.

class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    @classmethod
    def from_fahrenheit(cls, f):
        return cls(round((f - 32) * 5 / 9, 1))

    @staticmethod
    def is_freezing(celsius):
        return celsius <= 0

Temperature.from_fahrenheit(212).celsius   # 100.0
Temperature.is_freezing(-3)                # True
Tipo Primer argumento Úselo para
método de instancia yo Trabajar con los datos de un objeto
@classmethod cls Constructores alternativos
@staticmethod Ninguno Ayudantes relacionados con la clase.

Clases de datos

Cuando una clase contiene principalmente datos, escribir __init__, __repr__ y __eq__ a mano es tedioso. @dataclass los genera a partir de anotaciones de tipo:

from dataclasses import dataclass, field

@dataclass
class Item:
    name: str
    price: int
    tags: list = field(default_factory=list)

print(Item("Pen", 10))
print(Item("Pen", 10) == Item("Pen", 10))

# Item(name='Pen', price=10, tags=[])
# True

Consejo: No todo necesita una clase. Si no tiene estado y sólo un comportamiento, una función simple es más simple. Para búsquedas sencillas, un diccionario puede ser suficiente. Elija una clase cuando los datos y las reglas que los protegen claramente van de la mano.

Errores comunes

Usando un atributo de clase mutable

Este es un error clásico. La lista está definida en la clase, por lo que todos los carritos la comparten:

class Cart:
    items = []            # shared by every cart!

    def add(self, item):
        self.items.append(item)

c1, c2 = Cart(), Cart()
c1.add("pen")
print(c2.items)

# ['pen']

Créelo en __init__ con self.items = [], para que cada objeto tenga su propia lista.

Otros errores comunes

  • Olvidando self. Escriba self.balance, no balance, dentro de los métodos.
  • Olvidar super().__init__(). El niño entonces pierde los atributos establecidos por el padre.
  • Construyendo clases enormes. Una clase que hace de todo es difícil de probar. Divídalo por responsabilidad.
  • Herencia profunda. Dos niveles suelen ser suficientes y la composición suele ser más clara.
  • No escribir pruebas. Las clases con reglas son fáciles de probar, como muestra nuestro tutorial de pytest usando un carrito pequeño.

Conclusión

Python orientado a objetos se reduce a agrupar datos con el comportamiento que los protege. Comience con __init__, métodos y __str__, luego agregue herencia y propiedades cuando encuentre un problema que resuelvan. Como siguiente paso, tome un script que pase las mismas variables en todas partes y conviértalos en una clase pequeña.

Preguntas frecuentes

¿Cuál es la diferencia entre una clase y un objeto?

Una clase es la definición o modelo. Un objeto es una instancia específica creada a partir de él, con sus propios datos. Una clase puede crear muchos objetos.

¿Qué hace __init__ en Python?

Es el inicializador, que se ejecuta automáticamente cuando creas un objeto. Por lo general, establece los atributos iniciales del objeto a partir de los argumentos que pasa.

¿Qué es uno mismo en Python?

self se refiere al objeto sobre el que se invoca un método. Python lo pasa automáticamente y permite que el método lea y cambie los atributos de ese objeto.

¿Cuáles son los cuatro pilares de la programación orientada a objetos?

Son encapsulación, abstracción, herencia y polimorfismo. Juntos, le ayudan a agrupar datos con comportamiento, ocultar detalles y reutilizar código.

¿Cuándo debo usar una clase en lugar de una función?

Utilice una clase cuando los datos y el comportamiento vayan juntos en varias operaciones. Para una operación sin estado, una función simple es más sencilla y fácil de probar.

sigue aprendiendo

Trabajar con Stack Quora

¿Necesitas ayuda con pruebas, WordPress o SEO?

Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.

Sigue leyendo

Más guías sobre testing, IA y desarrollo moderno

¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.

Inteligencia artificial

Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas

Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…

Leer artículo →
DevOps

Explicación de las variables de entorno: archivos .env, secretos y configuración bien hechos

Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…

Leer artículo →
Desarrollo de software

Explicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429

La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …

Leer artículo →
Automatización de pruebas

Burlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan

Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…

Leer artículo →
Pruebas de software

Explicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%

Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…

Leer artículo →
Bases de datos y SQL

DELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno

DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…

Leer artículo →
Bases de datos y SQL

Vistas SQL explicadas: cree, use y evite los errores, con ejemplos

Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…

Leer artículo →
Desarrollo de software

Interfaz TypeScript versus tipo: diferencias reales, probadas con el compilador

Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…

Leer artículo →
Desarrollo de software

Python *args y **kwargs explicados: funciones flexibles con ejemplos claros

Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…

Leer artículo →
Desarrollo de software

Funciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas

Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…

Leer artículo →
Inteligencia artificial

¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar

¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…

Leer artículo →
DevOps

Monitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos

Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…

Leer artículo →
DevOps

Docker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta

Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…

Leer artículo →
Automatización de pruebas

TDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …

Leer artículo →
Pruebas de software

Pruebas de Aceptación de Usuario (UAT): Proceso, Lista de Verificación y Ejemplos Reales

Explicación de las pruebas de aceptación del usuario: quién las ejecuta, en qué se diferencia del control de calidad, un proceso de siete pasos, una…

Leer artículo →
Bases de datos y SQL

Valores NULL de SQL explicados: IS NULL, COALESCE, NULLIF y las trampas que se deben evitar

Los valores NULL de SQL se explican con las consultas que ejecutamos: lógica de tres valores, IS NULL, COALESCE, NULLIF, cómo los agregados, las uni…

Leer artículo →
Bases de datos y SQL

Declaración SQL CASE WHEN: sintaxis, ejemplos reales y errores comunes

CASO SQL CUANDO se explicó con las consultas que ejecutamos: formularios simples y buscados, orden de condiciones, pivotes con SUMA, trucos COUNT, c…

Leer artículo →
Desarrollo de software

¿Qué es JWT? Tokens web JSON explicados con un ejemplo práctico

¿Qué es JWT? JSON Web Tokens explicó: las tres partes, un token creado y manipulado en el código que ejecutamos, JWT vs sesiones, almacenamiento, to…

Leer artículo →
Desarrollo de software

Explicación del bucle de eventos de JavaScript: pila de llamadas, microtareas y temporizadores con ejemplos

El bucle de eventos de JavaScript explicado con el código que ejecutamos: pila de llamadas, colas de tareas y microtareas, por qué setTimeout 0 no e…

Leer artículo →
Desarrollo de software

Explicación de los generadores y el rendimiento de Python: ahorre memoria con ejemplos reales

Los generadores de Python y el rendimiento se explican con el código que ejecutamos: cómo se pausan y reanudan, midieron el ahorro de memoria, canal…

Leer artículo →
Inteligencia artificial

¿Qué son las incrustaciones? Los vectores y la similitud del coseno se explican de forma sencilla

¿Qué son las incrustaciones? Una guía en lenguaje sencillo sobre vectores, similitud de cosenos y búsqueda semántica, con un pequeño ejemplo que eje…

Leer artículo →
DevOps

Implementación azul-verde versus implementación canaria: diferencias, compensaciones y cómo elegir

Explicación de la implementación azul-verde versus canaria: cómo funciona cada uno, costo, riesgo y reversión, agrupación estable de usuarios que pr…

Leer artículo →
Automatización de pruebas

Pruebas inestables: qué las causa y cómo solucionarlas para siempre

Pruebas inestables explicadas con demostraciones que realizamos: las causas principales, cómo confirmar y diagnosticar una, correcciones adecuadas p…

Leer artículo →
Pruebas de software

Pruebas de carga frente a pruebas de estrés: diferencias, métricas y ejemplos de k6

Explicación de las pruebas de carga frente a las pruebas de estrés: qué prueba cada una, pruebas de picos y de absorción, las métricas que importan,…

Leer artículo →
Pruebas de software

Caso de prueba frente a escenario de prueba: diferencias clave, ejemplos y cuándo utilizar cada uno

Caso de prueba versus escenario de prueba explicado: definiciones claras, una tabla en paralelo, una función de restablecimiento de contraseña tomad…

Leer artículo →
Bases de datos y SQL

Optimización de consultas SQL: lea planes de ejecución y corrija consultas lentas, con tiempos

Optimización de consultas SQL probada en un millón de filas: lea planes de ejecución, agregue los índices correctos, corrija filtros no sargables, u…

Leer artículo →
Bases de datos y SQL

SQL UNION vs UNION ALL: diferencias, ejemplos y rendimiento probado

SQL UNION vs UNION ALL explicado con consultas que ejecutamos: duplicados, las reglas que siguen ambos, un error de datos real, rendimiento medido, …

Leer artículo →
Desarrollo de software

Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

Un tutorial de JavaScript Fetch API probado en un servidor local: GET y POST, por qué 404 no arroja, un asistente reutilizable, cadenas de consulta,…

Leer artículo →
Desarrollo de software

Manejo de archivos Python: lectura, escritura, CSV, JSON y pathlib con ejemplos

El manejo de archivos Python se explica con el código que ejecutamos: modos abiertos, lectura de archivos grandes, CSV, JSON, pathlib, archivos bina…

Leer artículo →
Desarrollo de software

Clases y objetos de Python: tutorial de programación orientada a objetos con ejemplos reales

Clases y objetos de Python explicados con el código que ejecutamos: __init__, métodos, atributos de clase versus instancia, herencia, propiedades, m…

Leer artículo →
Inteligencia artificial

¿Qué es un modelo de lenguaje grande? Cómo funcionan los LLM, explicados sin exageraciones

¿Qué es un modelo de lenguaje grande? Los LLM explicados en lenguaje sencillo: tokens, incrustaciones, atención, entrenamiento, ventanas de temperat…

Leer artículo →
DevOps

Comandos de Linux para principiantes: la guía esencial de terminal con ejemplos

Comandos de Linux para principiantes, agrupados por tarea: navegación, archivos, visualización de registros, grep, canalizaciones, permisos, proceso…

Leer artículo →
Automatización de pruebas

Selenium vs Playwright: diferencias clave, comparación de códigos y cuál elegir

Comparación de Selenium vs Playwright: arquitectura, espera, soporte de navegador e idioma, depuración, la misma prueba en ambas herramientas, conse…

Leer artículo →
Pruebas de software

Partición de equivalencia: técnica de diseño de pruebas explicada con ejemplos resueltos

Explicación de la partición de equivalencia: cómo encontrar particiones válidas e inválidas, ejemplos prácticos para edades, contraseñas y cupones, …

Leer artículo →
Pruebas de software

Severidad vs Prioridad en Pruebas de Software: Diferencias, Matriz y Ejemplos Reales

Explicación de gravedad versus prioridad en las pruebas de software: definiciones claras, una matriz de cuatro vías con ejemplos, escalas de niveles…

Leer artículo →
Bases de datos y SQL

Tutorial de subconsultas SQL: tipos, subconsultas correlacionadas y EXISTENCIAS con ejemplos

Un tutorial de subconsultas SQL con consultas que ejecutamos: subconsultas escalares, IN, FROM y SELECT, subconsultas correlacionadas, EXISTS, la tr…

Leer artículo →
Bases de datos y SQL

Transacciones SQL y ACID explicados: COMMIT, ROLLBACK y niveles de aislamiento

Transacciones SQL y ACID explicadas con una transferencia bancaria que ejecutamos: COMMIT, ROLLBACK, puntos de guardado, bloqueos, niveles de aislam…

Leer artículo →
Desarrollo de software

Git merge vs rebase: diferencias, ejemplos y cuándo usar cada uno

Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.

Leer artículo →
Desarrollo de software

List comprehension en Python: sintaxis, ejemplos y cuándo evitarla

List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.

Leer artículo →