Miembros públicos, protegidos y privados
Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 28 de 64.
Python tiene tres niveles de control de acceso para los miembros de una clase: público, protegido y privado. Estos controlan cómo se puede acceder a los atributos y métodos.
Aquí tienes un ejemplo de una clase con los tres niveles de acceso:
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Público - accesible desde cualquier lugar
self._balance = balance # Protegido - uso interno
self.__account_id = account_id # Privado - solo para la clase
def deposit(self, amount): # Método público
self._balance += amount
def _calculate_interest(self): # Método protegido
return self._balance * 0.02
def __validate_transaction(self, amount): # Método privado
return amount > 0 and amount <= self._balanceAccede a los miembros públicos desde cualquier lugar:
account = BankAccount("Alice", 1000, "12345")
print(account.owner) # Alice
account.deposit(500) # Funciona bienAccede a los miembros protegidos (guion bajo simple; solo por convención):
print(account._balance) # 1500 - funciona, pero no se recomienda
result = account._calculate_interest() # Funciona, pero no se recomienda
print(result) # 30.0Intenta acceder a los miembros privados (doble guion bajo: nombre alterado):
# Esto no funcionará:
# print(account.__account_id) # AttributeError
# Pero esto sí funciona (alteración de nombres):
print(account._BankAccount__account_id) # 12345Crea una subclase para mostrar la diferencia entre el acceso protegido y el privado:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Protegido - accesible desde una subclase
def show_id(self):
# return self.__account_id # Esto no funcionará - es privado
return "Cannot access private member"savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance()) # 2000
print(savings.show_id()) # No se puede acceder al miembro privadoResultado:
Alice
30.0
12345
2000
Cannot access private memberPunto clave: Los miembros públicos no tienen prefijo y son accesibles desde cualquier lugar. Los miembros protegidos usan un guion bajo (_) y solo deben utilizarse dentro de la jerarquía de clases. Los miembros privados usan dos guiones bajos (__) y sus nombres se modifican para ofrecer mayor privacidad. El control de acceso de Python se basa en convenciones y no se aplica de manera estricta.
Desafío
IntermedioEn este desafío, implementarás una clase BankAccount que demuestra el uso adecuado de los niveles de acceso público, protegido y privado en Python.
bankaccount.py- Contiene la definición de la clase con comentarios TODO que orientan tu implementación
- Sigue los comentarios TODO en
bankaccount.pypara implementar la funcionalidad requerida - Implementa los niveles de acceso adecuados (público, protegido y privado) según se especifica
- Asegúrate de que todos los métodos gestionen adecuadamente los casos límite (depósitos negativos, etc.)
Pruébalo tú mismo
from bank_account import BankAccount
# Gestor integral de casos de prueba
test_case = input()
if test_case == "basic_test":
# Prueba de funcionalidad básica
account = BankAccount("John Doe", "12345")
print(account.account_holder) # Atributo público
print(account.deposit(100)) # Método público
print(account.get_balance()) # Método público
elif test_case == "transaction_count":
# Prueba del atributo protegido
account = BankAccount("Jane Smith", "67890")
account.deposit(50)
account.deposit(100)
account.deposit(200)
print(account._transaction_count) # Atributo protegido
print(account.get_balance())
elif test_case == "invalid_deposit":
# Prueba de validación en el método deposit
account = BankAccount("Bob Johnson", "54321")
print(account.deposit(-50)) # Debería devolver None
print(account.deposit(0)) # Debería devolver None
print(account.deposit(75)) # Debería devolver 75
print(account.get_balance())
elif test_case == "private_access":
# Prueba de acceso a atributos privados
account = BankAccount("Alice Brown", "98765")
try:
print(account.__balance) # Esto provocará un AttributeError
except AttributeError:
pass
try:
print(account.__account_number) # Esto provocará un AttributeError
except AttributeError:
pass
print("Private attributes are not directly accessible")
account.deposit(500)
print(account.get_balance()) # Acceso mediante un método público
elif test_case == "name_mangling":
# Demostración de la modificación de nombres para atributos privados
account = BankAccount("Charlie Green", "13579")
print(account._BankAccount__balance) # Acceso a un atributo privado mediante la modificación de nombres
print(account._BankAccount__account_number) # Acceso a un atributo privado mediante la modificación de nombres
account.deposit(300)
print(account._BankAccount__balance) # Debería mostrar el saldo actualizado
elif test_case == "multiple_accounts":
# Prueba de varias cuentas
account1 = BankAccount("David White", "24680")
account2 = BankAccount("Eva Black", "86420")
account3 = BankAccount("Frank Red", "97531")
account1.deposit(150)
account2.deposit(250)
account2.deposit(50)
account3.deposit(500)
account3.deposit(300)
account3.deposit(200)
print(f"{account1.account_holder}: {account1.get_balance()}")
print(f"{account2.account_holder}: {account2.get_balance()}")
print(f"{account3.account_holder}: {account3.get_balance()}")
print(f"Account 1 transactions: {account1._transaction_count}")
print(f"Account 2 transactions: {account2._transaction_count}")
print(f"Account 3 transactions: {account3._transaction_count}")
elif test_case == "stress_test":
# Prueba de rendimiento con muchas transacciones
account = BankAccount("Stress Tester", "11111")
for _ in range(1000):
account.deposit(1)
print(f"Final balance: {account.get_balance()}")
print(f"Transaction count: {account._transaction_count}")
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la POO
Introducción a la POOArchivos externosClases vs. objetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Repaso: calculadora sencilla4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosRepaso: jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso: lista personalizada10Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador de propiedadDecorador de método estáticoDecorador de método de clase5Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas8Conceptos avanzados de POO
Composición frente a herenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs. variables de claseDecoradores de propiedadesAtributos privadosRepaso: gestor de cuentas bancarias6Encapsulamiento
Miembros públicos, protegidos y privadosModificadores de accesoOcultación de informaciónDecoradores de propiedades avanzadosRepaso: sistema de registros de estudiantesPractica por tu cuenta: Compilador de Python online