¿Te sientes confundido al intentar entender las clases en Python?

La Programación Orientada a Objetos (POO) es el muro donde muchas personas se detienen. El problema no es la teoría, sino pequeños vicios de lógica que arrastramos de la programación secuencial.

En este post, vamos a desmenuzarlos para que hoy mismo escribas código más limpio y profesional.

Lo que vas a aprender hoy

  1. Por qué olvidar el self es el error más común.
  2. La diferencia entre atributos de clase e instancia.
  3. Cómo usar correctamente el método __init__.
  4. Por qué heredar no siempre es la solución.

1. El gran ausente: Olvidar el self

Este es el error más frecuente. En Python, el primer parámetro de cualquier método dentro de una clase debe ser self.

El error común:

class Estudiante:
    def saludar(): # Error: falta 'self'
        print("¡Hola, soy de San Marcos!")

La solución:

self representa a la instancia específica que está llamando al método. Sin él, Python no sabe a qué objeto te refieres.

class Estudiante:
    def saludar(self): # Correcto
        print("¡Hola, soy de San Marcos!")

Tip: No tienes que llamar a self cuando usas el método. Python lo pasa automáticamente por ti

2. Confundir Atributos de Clase con Instancia

Imagina que creas una clase Alumno. Si defines una variable fuera del __init__, todos los alumnos compartirán la misma variable. ¡Cuidado con esto!

El error (Estado compartido accidental):

class Alumno:
    notas = [] # Atributo de clase (compartido por TODOS)

pedro = Alumno()
pedro.notas.append(20)

ana = Alumno()
print(ana.notas) # ¡Salida: [20]! Ana heredó la nota de Pedro.

La solución:

Define siempre las variables que cambian por objeto dentro del constructor __init__.

class Alumno:
    def __init__(self):
        self.notas = [] # Atributo de instancia (único para cada uno)

3. El “Mal de la Herencia”

Muchos alumnos creen que para usar el código de otra clase, deben heredar de ella. Esto crea jerarquías imposibles de mantener.

Regla de oro: Usa herencia solo si puedes decir que el Objeto B “es un” Objeto A.

  • ¿Un Profesor es un Usuario? Sí. (Hereda)
  • ¿Un Curso es una ListaDeAlumnos? No, un curso tiene una lista. (Composición)

4. No usar los Métodos “Dunder” (str)

¿Alguna vez has impreso un objeto y te ha salido algo como <__main__.Alumno object at 0x7f...>? Es frustrante, ¿verdad?

Muchos personas ignoran que Python te permite personalizar cómo se ve tu objeto simplemente añadiendo el método __str__.

class Alumno:
    def __init__(self, nombre):
        self.nombre = nombre
        
    def __str__(self):
        return f"Alumno de San Marcos: {self.nombre}"

# Ahora:
yo = Alumno("Miguel")
print(yo) # Salida: Alumno de San Marcos: Miguel

Conclusión: Tu checklist para dominar la POO

Dominar la POO puede ser dificil al comienzo: a veces nos suena extraño, pero luego te permite hacer cosas más complejas con mucha claridad. Para que tu código sea profesional, recuerda siempre estos puntos:

  1. self siempre va primero en la definición de tus métodos.
  2. Usa __init__ para datos únicos de cada objeto, evitando estados compartidos accidentales.
  3. Prefiere la composición sobre la herencia a menos que haya una relación clara de “es un”.
  4. Usa __str__ para que tus objetos sean fáciles de leer y depurar.