La importancia del encapsulamiento radica en varios aspectos clave:
Python ofrece varios mecanismos para implementar el encapsulamiento. Exploremos estos con ejemplos:
En Python, podemos crear atributos privados prefijando el nombre del atributo con doble guion bajo (__
). Esto activa el “name mangling”, que hace que el atributo sea más difícil de acceder desde fuera de la clase.
class CuentaBancaria:
def __init__(self, numero_cuenta, saldo):
self.__numero_cuenta = numero_cuenta # Atributo privado
self.__saldo = saldo # Atributo privado
def depositar(self, cantidad):
if cantidad > 0:
self.__saldo += cantidad
return True
return False
def retirar(self, cantidad):
if 0 < cantidad <= self.__saldo:
self.__saldo -= cantidad
return True
return False
def obtener_saldo(self):
return self.__saldo
# Uso
cuenta = CuentaBancaria("1234567890", 1000)
print(cuenta.obtener_saldo()) # Salida: 1000
cuenta.depositar(500)
print(cuenta.obtener_saldo()) # Salida: 1500
cuenta.retirar(200)
print(cuenta.obtener_saldo()) # Salida: 1300
# Esto generará un AttributeError
# print(cuenta.__saldo)
En este ejemplo:
__numero_cuenta
y __saldo
son atributos privados.depositar
, retirar
, obtener_saldo
) para interactuar con estos atributos privados.__saldo
desde fuera de la clase generará una excepción AttributeError
.El decorador @property
de Python nos permite definir métodos que pueden ser accedidos como atributos, proporcionando una forma más pythonica de implementar getters y setters.
class Circulo:
def __init__(self, radio):
self._radio = radio
@property
def radio(self):
return self._radio
@radio.setter
def radio(self, valor):
if valor > 0:
self._radio = valor
else:
raise ValueError("El radio debe ser positivo")
@property
def area(self):
return 3.14159 * self._radio ** 2
# Uso
circulo = Circulo(5)
print(circulo.radio) # Salida: 5
print(circulo.area) # Salida: 78.53975
circulo.radio = 7
print(circulo.radio) # Salida: 7
print(circulo.area) # Salida: 153.93791
# Esto generará un ValueError
# circulo.radio = -1
En este ejemplo:
_radio
es un atributo protegido (el guion bajo simple es una convención para atributos protegidos en Python).radio
proporciona acceso de lectura y escritura a _radio
con validación.area
es de solo lectura y se calcula al vuelo.Los beneficios del encapsulamiento son numerosos:
Las mejores prácticas para el encapsulamiento en Python incluyen:
Veamos un ejemplo más complejo que demuestra estas prácticas:
class Empleado:
def __init__(self, nombre, salario):
self.__nombre = nombre
self.__salario = salario
self.__proyectos = []
@property
def nombre(self):
return self.__nombre
@property
def salario(self):
return self.__salario
@salario.setter
def salario(self, valor):
if valor > 0:
self.__salario = valor
else:
raise ValueError("El salario debe ser positivo")
def agregar_proyecto(self, proyecto):
"""
Agrega un proyecto a la lista de proyectos del empleado.
:param proyecto: cadena que representa el nombre del proyecto
"""
self.__proyectos.append(proyecto)
def eliminar_proyecto(self, proyecto):
"""
Elimina un proyecto de la lista de proyectos del empleado.
:param proyecto: cadena que representa el nombre del proyecto
:return: True si el proyecto fue eliminado, False si no se encontró
"""
if proyecto in self.__proyectos:
self.__proyectos.remove(proyecto)
return True
return False
@property
def cantidad_proyectos(self):
return len(self.__proyectos)
def __str__(self):
return f"Empleado: {self.__nombre}, Salario: ${self.__salario}, Proyectos: {self.cantidad_proyectos}"
# Uso
emp = Empleado("Juan Pérez", 50000)
print(emp.nombre) # Salida: Juan Pérez
print(emp.salario) # Salida: 50000
emp.agregar_proyecto("Proyecto A")
emp.agregar_proyecto("Proyecto B")
print(emp.cantidad_proyectos) # Salida: 2
emp.salario = 55000
print(emp) # Salida: Empleado: Juan Pérez, Salario: $55000, Proyectos: 2
emp.eliminar_proyecto("Proyecto A")
print(emp.cantidad_proyectos) # Salida: 1
# Esto generará un AttributeError
# print(emp.__proyectos)
Este ejemplo demuestra:
__nombre
, __salario
, __proyectos
)nombre
, salario
, cantidad_proyectos
)agregar_proyecto
, eliminar_proyecto
)__str__
personalizado para una representación de cadena agradable del objetoSiguiendo estas prácticas, creamos una clase que es flexible y robusta, encarnando el principio de encapsulamiento.
¡Felicitaciones por llegar hasta acá! Espero que este recorrido por el universo de la programación te haya resultado tan interesante como lo fue para mí al escribirlo.
Queremos conocer tu opinión, así que no dudes en compartir tus comentarios, sugerencias y esas ideas brillantes que seguro tenés.
Además, para explorar más allá de estas líneas, date una vuelta por los ejemplos prácticos que armamos para vos. Todo el código y los proyectos los encontrarás en nuestro repositorio de GitHub learn-software-engineering/examples.
Gracias por ser parte de esta comunidad de aprendizaje. ¡Seguí programando y explorando nuevas areas en este fascinante mundo del software!
¿Fue útil esta página?
¡Nos alegra mucho! Por favor dinos como podemos mejorar.
Nos apena que no te haya gustado. Por favor dinos como podemos mejorar.