Clases y Objetos en Python
Aprende cómo funcionan las clases y objetos en Python: define clases, usa __init__, crea instancias, trabaja con atributos y métodos, y entiende la herencia.
Python es un lenguaje de programación orientada a objetos (OOP), lo que significa que organiza el código alrededor de objetos en lugar de solo funciones. Una clase es el plano que describe qué datos contiene un object y qué puede hacer. Un object es una instancia específica creada a partir de ese plano.
Este capítulo cubre:
- Qué son las clases y los objetos, y por qué importan
- Definir una clase con
__init__, atributos de instancia y métodos - Atributos de clase versus atributos de instancia
- Crear y usar objetos
- Modificar y eliminar atributos
- Comprobar tipos de objetos con
isinstance() - Una primera mirada a la herencia
Para profundizar en la herencia, consulta Herencia en Python. Para patrones OOP más avanzados, consulta Clases Base Abstractas en Python.
¿Qué Es una Clase?
Piensa en una clase como un cortador de galletas y en un object como la galleta. Defines la forma una vez (la clase), y luego produces tantas galletas (objetos) como necesites. Cada object comparte la misma estructura pero contiene sus propios datos.
class Dog:
pass # an empty class — valid but not very useful yetLa palabra clave class seguida de un nombre y dos puntos crea una nueva clase. Por convención, los nombres de clase usan CapWords (también llamado PascalCase): MyClass, BankAccount, HttpRequest.
El Método __init__
El método __init__ (abreviatura de initialise) se ejecuta automáticamente cada vez que creas un nuevo object. Establece el estado inicial del object asignando valores a sus atributos de instancia.
class Dog:
def __init__(self, name, age):
self.name = name # instance attribute
self.age = age # instance attributeEl primer parámetro siempre es self — hace referencia al object que se está creando. Python lo pasa automáticamente; nunca lo proporcionas tú mismo.
Atributos de Instancia vs. Atributos de Clase
| Tipo | Definido dentro de | Pertenece a | ¿Compartido? |
|---|---|---|---|
| Atributo de instancia | __init__ (mediante self) | Cada object | No — cada object tiene su propia copia |
| Atributo de clase | Cuerpo de la clase (fuera de cualquier método) | La clase misma | Sí — todos los objetos comparten una copia |
class Dog:
species = "Canis familiaris" # class attribute — shared by all Dogs
def __init__(self, name, age):
self.name = name # instance attribute
self.age = age # instance attribute
fido = Dog("Fido", 3)
bella = Dog("Bella", 5)
print(fido.species) # Canis familiaris
print(bella.species) # Canis familiaris (same class attribute)
print(fido.name) # Fido
print(bella.name) # Bella (different instance attributes)Usa un atributo de clase cuando un valor es el mismo para todos los objetos de ese tipo (p. ej., la especie de todos los perros). Usa atributos de instancia para datos que varían por object.
Definición de Métodos
Un método es una función definida dentro de una clase. Al igual que __init__, siempre toma self como primer parámetro para que pueda acceder a los propios atributos del object.
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
return f"{self.name} says: Woof!"
def description(self):
return f"{self.name} is {self.age} years old."Llamas a un método en un object usando notación de punto — Python pasa automáticamente el object como self:
fido = Dog("Fido", 3)
print(fido.bark()) # Fido says: Woof!
print(fido.description()) # Fido is 3 years old.El Método __str__
Python llama a __str__ cuando pasas un object a print() o str(). Sin él, obtienes una dirección poco útil como <__main__.Dog object at 0x...>. Definirlo hace que la depuración sea mucho más fácil.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Dog(name={self.name!r}, age={self.age})"
fido = Dog("Fido", 3)
print(fido) # Dog(name='Fido', age=3)Crear y Usar Objetos
Crear un object se llama instanciación. Llamas a la clase como una función, pasando los argumentos que __init__ espera (excluyendo self):
Puedes crear tantos objetos como necesites desde la misma clase — cada uno es independiente:
class Rectangle:
def __init__(self, width, height=1):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
r1 = Rectangle(4, 3)
r2 = Rectangle(5) # height defaults to 1
print(r1.area()) # 12
print(r1.perimeter()) # 14
print(r2.area()) # 5Observa que height=1 proporciona un valor por defecto: si omites el segundo argumento, Python usa 1 automáticamente.
Modificar y Eliminar Atributos
Puedes cambiar o añadir atributos a un object después de que haya sido creado, y eliminarlos con del:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Alice", 30)
print(p.age) # 30
p.age = 31 # modify an existing attribute
print(p.age) # 31
p.email = "[email protected]" # add a new attribute at runtime
print(p.email) # [email protected]
del p.email # delete the attribute
# print(p.email) # would raise AttributeErrorAunque Python permite agregar atributos libremente, es más limpio declarar todos los atributos dentro de __init__ para que la estructura de la clase sea obvia de un vistazo.
Comprobación de Tipos de Objetos
Usa isinstance() para comprobar si un object es una instancia de una clase en particular. Devuelve True para la clase en sí y para cualquiera de sus clases padre:
class Animal:
pass
class Dog(Animal):
pass
rex = Dog()
print(isinstance(rex, Dog)) # True
print(isinstance(rex, Animal)) # True — Dog is a subclass of Animal
print(type(rex) is Dog) # True
print(type(rex) is Animal) # False — type() does not climb the hierarchyPrefiere isinstance() sobre type() is en la mayoría del código porque maneja correctamente las subclases.
Una Primera Mirada a la Herencia
La herencia permite que una nueva clase reutilice y extienda el comportamiento de una existente. La nueva clase (hija o subclase) obtiene automáticamente todos los atributos y métodos de la clase padre:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound."
class Dog(Animal):
def speak(self): # override the parent method
return f"{self.name} says: Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says: Meow!"
dog = Dog("Rex")
cat = Cat("Whiskers")
print(dog.speak()) # Rex says: Woof!
print(cat.speak()) # Whiskers says: Meow!
print(isinstance(dog, Animal)) # TrueTanto Dog como Cat heredan __init__ de Animal, por lo que no necesitan repetirlo. Solo sobreescriben speak() para proporcionar un comportamiento específico de cada raza.
Para un tratamiento completo de la herencia — incluyendo super(), herencia múltiple y el orden de resolución de métodos — consulta Herencia en Python.
¿Cuándo Deberías Usar una Clase?
Las clases tienen más sentido cuando:
- Tienes datos y comportamiento que pertenecen juntos (una cuenta bancaria que sabe cómo hacer depósitos y retiros).
- Necesitas múltiples objetos independientes del mismo tipo (muchos objetos
Dog, cada uno con nombres y edades diferentes). - Quieres modelar entidades del mundo real con una identidad clara.
Las funciones de utilidad simples que solo transforman una entrada en una salida a menudo son mejores como funciones simples. Python no requiere que todo esté en una clase.
Resumen
| Concepto | Qué hace |
|---|---|
class | Define un nuevo tipo |
__init__ | Inicializa los atributos de instancia cuando se crea un object |
self | Hace referencia al object actual dentro de un método |
| Atributo de instancia | Datos que pertenecen a un object específico |
| Atributo de clase | Datos compartidos entre todos los objetos de la clase |
| Método | Una función definida dentro de una clase; siempre recibe self |
__str__ | Controla cómo print() muestra el object |
isinstance() | Comprueba si un object es instancia de una clase o sus subclases |
| Herencia | Permite que una clase hija reutilice y extienda una clase padre |