Atributos y métodos de clase
Introducción
Los atributos y métodos son componentes fundamentales de las clases en Python, ya que definen las características (datos) y comportamientos (funciones) que tendrán los objetos creados a partir de ellas. Entender cómo definir y utilizar estos elementos es esencial para aprovechar al máximo la programación orientada a objetos. En este artículo, exploraremos en detalle los distintos tipos de atributos y métodos que pueden existir en una clase de Python, así como las mejores prácticas para su implementación.
Atributos de clase
Los atributos de clase son variables que pertenecen a la clase en sí misma, no a las instancias (objetos) creadas a partir de ella. Estos atributos son compartidos por todas las instancias de la clase.
class Empleado:
# Atributo de clase
empresa = "Tecnología Española S.A."
def __init__(self, nombre, salario):
# Atributos de instancia
self.nombre = nombre
self.salario = salario
# Creamos dos empleados
empleado1 = Empleado("Ana", 30000)
empleado2 = Empleado("Carlos", 35000)
# Accedemos al atributo de clase
print(Empleado.empresa) # Output: Tecnología Española S.A.
print(empleado1.empresa) # Output: Tecnología Española S.A.
print(empleado2.empresa) # Output: Tecnología Española S.A.
# Si modificamos el atributo de clase, cambia para todos
Empleado.empresa = "Nueva Empresa S.L."
print(empleado1.empresa) # Output: Nueva Empresa S.L.
print(empleado2.empresa) # Output: Nueva Empresa S.L.
Características importantes de los atributos de clase:
- Se definen fuera de cualquier método en el cuerpo de la clase
- Se accede a ellos mediante
NombreClase.atributo
oinstancia.atributo
- Son útiles para definir constantes o valores compartidos por todas las instancias
- Ocupan memoria una sola vez, independientemente del número de instancias
Atributos de instancia
Los atributos de instancia son variables que pertenecen a cada objeto (instancia) creado a partir de la clase. Cada instancia tiene su propia copia independiente de estos atributos.
class Coche:
# Atributo de clase
ruedas = 4
def __init__(self, marca, modelo, color):
# Atributos de instancia
self.marca = marca
self.modelo = modelo
self.color = color
self.kilometraje = 0 # Valor inicial
def conducir(self, km):
self.kilometraje += km
print(f"El {self.marca} {self.modelo} ha recorrido {km} km")
# Creamos dos coches
mi_coche = Coche("Seat", "Ibiza", "rojo")
otro_coche = Coche("Renault", "Clio", "azul")
# Cada coche tiene sus propios atributos de instancia
print(mi_coche.marca) # Output: Seat
print(otro_coche.marca) # Output: Renault
# Modificamos un atributo de instancia
mi_coche.conducir(100)
print(mi_coche.kilometraje) # Output: 100
print(otro_coche.kilometraje) # Output: 0 (No se modifica)
Características importantes de los atributos de instancia:
- Se definen dentro del método
__init__
o en otros métodos usandoself
- Se accede a ellos mediante
instancia.atributo
- Cada instancia tiene su propia copia, independiente de otras instancias
- Se pueden crear nuevos atributos para una instancia específica en cualquier momento
Métodos de instancia
Los métodos de instancia son funciones definidas dentro de una clase que operan sobre una instancia específica. Siempre reciben self
como primer parámetro, que representa la instancia sobre la que actúan.
class Calculadora:
def __init__(self, marca):
self.marca = marca
self.resultado = 0
# Métodos de instancia
def sumar(self, valor):
self.resultado += valor
return self.resultado
def restar(self, valor):
self.resultado -= valor
return self.resultado
def reiniciar(self):
self.resultado = 0
return self.resultado
def mostrar_info(self):
return f"Calculadora {self.marca} - Resultado actual: {self.resultado}"
# Creamos una calculadora
mi_calc = Calculadora("Casio")
# Usamos sus métodos
print(mi_calc.sumar(10)) # Output: 10
print(mi_calc.sumar(5)) # Output: 15
print(mi_calc.restar(7)) # Output: 8
print(mi_calc.mostrar_info()) # Output: Calculadora Casio - Resultado actual: 8
mi_calc.reiniciar()
print(mi_calc.resultado) # Output: 0
Características importantes de los métodos de instancia:
- Siempre reciben
self
como primer parámetro - Pueden acceder y modificar atributos de instancia usando
self
- Pueden llamar a otros métodos de la instancia usando
self
- Se invocan mediante
instancia.metodo(argumentos)
Métodos de clase
Los métodos de clase están ligados a la clase en sí misma, no a sus instancias. Se definen utilizando el decorador @classmethod
y reciben como primer parámetro cls
(por convención), que representa la clase.
class Fecha:
def __init__(self, dia, mes, año):
self.dia = dia
self.mes = mes
self.año = año
def mostrar(self):
return f"{self.dia}/{self.mes}/{self.año}"
@classmethod
def desde_cadena(cls, cadena_fecha):
# Crea una instancia de Fecha a partir de una cadena formato "dia-mes-año"
dia, mes, año = map(int, cadena_fecha.split('-'))
return cls(dia, mes, año)
@classmethod
def hoy(cls):
# En un caso real importaríamos datetime para obtener la fecha actual
return cls(21, 4, 2025) # Fecha de ejemplo
# Creamos instancias de diferentes formas
fecha1 = Fecha(15, 3, 2025)
fecha2 = Fecha.desde_cadena("25-12-2025")
fecha3 = Fecha.hoy()
print(fecha1.mostrar()) # Output: 15/3/2025
print(fecha2.mostrar()) # Output: 25/12/2025
print(fecha3.mostrar()) # Output: 21/4/2025
Características importantes de los métodos de clase:
- Se definen con el decorador
@classmethod
- Reciben
cls
como primer parámetro (la clase misma) - Pueden acceder a atributos de clase pero no a atributos de instancia
- Pueden crear y devolver nuevas instancias de la clase
- Se invocan mediante
Clase.metodo(argumentos)
oinstancia.metodo(argumentos)
- Son útiles para definir métodos alternativos de construcción
Métodos estáticos
Los métodos estáticos no tienen acceso ni a la instancia ni a la clase. Se definen usando el decorador @staticmethod
y funcionan como funciones regulares dentro del espacio de nombres de la clase.
class Matematicas:
@staticmethod
def es_primo(numero):
if numero <= 1:
return False
if numero <= 3:
return True
if numero % 2 == 0 or numero % 3 == 0:
return False
i = 5
while i * i <= numero:
if numero % i == 0 or numero % (i + 2) == 0:
return False
i += 6
return True
@staticmethod
def factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * Matematicas.factorial(n - 1)
# Usamos los métodos estáticos directamente desde la clase
print(Matematicas.es_primo(17)) # Output: True
print(Matematicas.es_primo(20)) # Output: False
print(Matematicas.factorial(5)) # Output: 120
# También podemos usar los métodos estáticos desde una instancia
mat = Matematicas()
print(mat.es_primo(23)) # Output: True
print(mat.factorial(4)) # Output: 24
Características importantes de los métodos estáticos:
- Se definen con el decorador
@staticmethod
- No reciben automáticamente ningún primer argumento especial (
self
ocls
) - No pueden acceder directamente a atributos de clase o de instancia
- Son útiles para funciones relacionadas con la clase pero que no necesitan acceder a sus atributos
- Se invocan mediante
Clase.metodo(argumentos)
oinstancia.metodo(argumentos)
Acceso a atributos y métodos
En Python, por defecto, todos los atributos y métodos de una clase son públicos y pueden ser accedidos desde fuera de la clase. Sin embargo, existe una convención para indicar que ciertos elementos deberían considerarse privados:
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre # Atributo público
self._edad = edad # Atributo "protegido" (convención)
self.__dni = None # Atributo "privado" (name mangling)
def establecer_dni(self, numero):
# Verificación simplificada (en un caso real sería más compleja)
if len(numero) == 9:
self.__dni = numero
return True
return False
def obtener_dni(self):
return "***" + self.__dni[-4:] if self.__dni else None
persona = Persona("Laura", 35)
print(persona.nombre) # Acceso normal: Output: Laura
print(persona._edad) # Técnicamente funciona, pero no es recomendable: Output: 35
# print(persona.__dni) # Esto generaría un error
# Forma correcta de interactuar con atributos "privados"
persona.establecer_dni("123456789")
print(persona.obtener_dni()) # Output: ***6789
Notas sobre la convención de nombrado:
- Un guion bajo al inicio (
_atributo
): Indica que el atributo es "protegido" y no debería accederse directamente desde fuera (aunque técnicamente es posible) - Dos guiones bajos al inicio (
__atributo
): Activa el "name mangling", renombrando internamente el atributo a_NombreClase__atributo
, dificultando el acceso directo
Resumen
Los atributos y métodos son los bloques fundamentales de las clases en Python, que permiten definir tanto las características (datos) como los comportamientos (acciones) de los objetos. Hemos visto varios tipos:
- Atributos de clase: Compartidos por todas las instancias, definidos directamente en la clase
- Atributos de instancia: Propios de cada objeto, definidos generalmente dentro de
__init__
conself
- Métodos de instancia: Operan sobre una instancia específica, reciben
self
- Métodos de clase: Vinculados a la clase y no a instancias, usan
@classmethod
y recibencls
- Métodos estáticos: Funciones regulares dentro del espacio de nombres de la clase, usan
@staticmethod
En el siguiente artículo, profundizaremos en el método constructor __init__
, uno de los métodos especiales más importantes en la programación orientada a objetos en Python, que nos permite inicializar correctamente los objetos al momento de su creación.