Aprende leyendo en orden

Herencia de clases — Reutilizar funciones de una clase existente

Aprende la herencia de clases en Python. Hereda atributos y métodos con class Hijo(Padre):, sobrescribe métodos y llama a la versión del padre con super() — todo con diagramas.

La última vez usamos métodos especiales como __add__ y __str__ para enseñar operaciones nativas a nuestras propias clases. Esta vez cubrimos una de las ideas centrales de la POO: la herencia de clases.

¿Por qué usar la herencia?

Cuando construyes apps, te encuentras a menudo con clases casi iguales pero que difieren en algunos puntos. Imagina Customer, Employee y Admin — todas tienen un name y un email y devuelven un greeting(), pero cada una tiene unos cuantos atributos o métodos extra.

Podrías escribir los mismos name / email / greeting() en las tres clases — pero el código quedaría duplicado y cada cambio tendría que hacerse en tres lugares. La solución limpia es poner las partes compartidas en una clase padre y hacer que cada clase hija «herede del padre y solo escriba las diferencias». Eso es la herencia.

Subir el código compartido al padre
Person(padre)name / agegreeting()Employee(hijo)hereda
Los atributos y métodos compartidos viven en la clase padre (Person). Solo las diferencias van en el hijo (Employee). No hace falta volver a declarar name o greeting cada vez.

Heredar de un padre — class Hijo(Padre):

La sintaxis es simple: cuando defines una subclase, pon la clase padre entre paréntesis después del nombre de la clase. La subclase recoge automáticamente todos los atributos y métodos del padre.

Abajo, Person es el padre (con name, age y un greeting) y Employee es el hijo. Employee no define ni un solo método propio, pero llamar a greeting() simplemente funciona gracias a la herencia.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hola, {self.name}")

    def say_age(self):
        print(f"{self.age} años")


class Employee(Person):       # hereda de Person
    pass                       # el cuerpo puede estar vacío


e = Employee("Ana", 45)
e.greeting()                  # Hola, Ana   <- método del padre
e.say_age()                   # 45 años
El hijo obtiene todo lo que tiene el padre
Person (padre)
  • Atributos: name / age
  • Métodos: greeting() / say_age()
  • __init__(self, name, age)
Employee (hijo)
  • El cuerpo está vacío (solo pass)
  • Hereda atributos y métodos del padre
  • Employee("Ana", 45) llama al __init__ del padre
Aun cuando el hijo está vacío, todo lo que tiene el padre está disponible. Reutilizar el comportamiento sin reescribirlo es el sentido de la herencia.

Construye un padre Person y un Employee que solo herede de él.

① Define class Person: con __init__(self, name, age) que asigne self.name y self.age.

② Dentro de Person, define greeting(self) que ejecute print(f"Hola, {self.name}").

③ Escribe class Employee(Person): con solo pass como cuerpo.

④ Construye e = Employee("Ana", 45) y llama a e.greeting().

(Cuando se ejecute correctamente, aparecerá la explicación.)

Editor Python

Ejecutar el código para ver el resultado

Sobrescritura de métodos — Reemplazar con el mismo nombre

Solo herencia te da el comportamiento del padre sin cambios. Pero si escribes un método con el mismo nombre en la clase hija, la versión del hijo tiene prioridad. Eso es una sobrescritura (override).

Por ejemplo, para darle a Employee un saludo diferente como «Hola, Empleado Ana», redefine greeting en el hijo. Llamarlo en una instancia de Person da el saludo del padre; llamarlo en una instancia de Employee da el del hijo. El comportamiento cambia según a qué clase pertenece la instancia que llama.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hola, {self.name}")


class Employee(Person):
    def greeting(self):                # mismo nombre = sobrescritura
        print(f"Hola, Empleado {self.name}")


p = Person("Carlos", 30)
e = Employee("Ana", 45)
p.greeting()    # Hola, Carlos
e.greeting()    # Hola, Empleado Ana    <- gana la versión del hijo
Orden de búsqueda de métodos
e.greeting()greeting enEmployee?encontrado→ ejecutagreeting enPerson?ejecuta si está,si no error① buscasi No
Python busca el método en la clase hija primero. Si no está ahí, sube al padre. Mismo nombre → gana el hijo — eso es sobrescritura.

Agrega una sobrescritura de greeting al código previo.

① Construye la misma clase Person que antes (__init__ y greeting).

② Define class Employee(Person): y dentro redefine greeting(self) para ejecutar print(f"Hola, Empleado {self.name}").

③ Construye un Person("Carlos", 30) y un Employee("Ana", 45), luego llama a greeting() en cada uno y compara.

Editor Python

Ejecutar el código para ver el resultado

super() — Llamar al método del padre

A veces quieres sobrescribir un método pero seguir basándote en el comportamiento del padre. Ahí entra super(). Escribir super().method() llama al método del mismo nombre en el padre de la clase actual.

Por ejemplo, supón que quieres «el greeting del padre (que imprime Hola, Ana) seguido de una línea extra en el hijo». Dentro del greeting del hijo, llama primero a super().greeting() y luego añade tu propia línea.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hola, {self.name}")


class Employee(Person):
    def greeting(self):
        super().greeting()                            # ① ejecuta primero el greeting del padre
        print(f"Soy Empleado {self.name}")            # ② luego la línea propia del hijo


Employee("Ana", 45).greeting()
# Hola, Ana
# Soy Empleado Ana
super().greeting() reutiliza la lógica del padre
Employee.greeting()cuerpo delgreeting hijosuper().greeting()ejecuta elgreeting padreresto delcuerpo hijollamadoejec.
Dentro del greeting del hijo, llamar a super().greeting() ejecuta el greeting del padre directamente. self se pasa automáticamente — no lo escribes.

Sobrescribir __init__ para añadir más atributos

Donde super() brilla más es cuando sobrescribes __init__. Imagina que la clase hija necesita los atributos del padre más algunos propios — por ejemplo, Employee también debería llevar un phone_number.

En ese caso redefines __init__ en el hijo, pero la inicialización del padre (self.name = name etc.) se gestiona en una línea con super().__init__(name, age), y añades los atributos extra después. Así no tienes que repetir las asignaciones de name / age.

El __init__ hijo construye atributos del padre y del hijo
Employee("Ana", 45, "555-1111")__init__ hijose ejecutasuper().__init__(name, age)el padre asignaname / ageself.phone_number= phone_numberatributos padre + hijolistosllamado
Llamar a Employee(...) ejecuta el __init__ del hijo → super().__init__(name, age) deja que el padre asigne name / age → luego el hijo añade phone_number. Estado final: atributos padre + hijo todos en su lugar.
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age


class Employee(Person):
    def __init__(self, name, age, phone_number):
        super().__init__(name, age)               # ① el padre define name / age
        self.phone_number = phone_number           # ② añade el atributo solo del hijo

    def show(self):
        print(f"{self.name} / {self.age} / {self.phone_number}")


Employee("Ana", 45, "555-1111").show()
# Ana / 45 / 555-1111

Olvida super().__init__(...) y los atributos desaparecen

Si sobrescribes __init__ pero olvidas llamar a super().__init__(...), las asignaciones del padre como self.name = name nunca ocurren. La próxima vez que leas self.name, obtienes un AttributeError. Cada vez que sobrescribes __init__ en una clase hija, llama a super().__init__(...) justo arriba — hazlo costumbre.

Añade un phone_number a Employee sobrescribiendo __init__.

① Define class Person: con __init__(self, name, age) que asigne self.name y self.age.

② Define class Employee(Person): con __init__(self, name, age, phone_number). Dentro, llama primero a super().__init__(name, age), luego self.phone_number = phone_number.

③ Dentro de Employee, define show(self) que ejecute print(f"{self.name} / {self.age} / {self.phone_number}").

④ Construye Employee("Ana", 45, "555-1111") y llama a show().

Editor Python

Ejecutar el código para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Cuál de las siguientes es la forma correcta de hacer que Dog herede de Animal?

Pregunta 2¿Cuál es la descripción más precisa de la sobrescritura de método?

Pregunta 3Si olvidas llamar a super().__init__(...) en el __init__ del hijo, ¿qué pasa?