Miembros públicos, protegidos y privados
Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 28 de 64.
Python tiene tres niveles de control de acceso para los miembros de la clase: público, protegido y privado. Estos controlan cómo se puede acceder a los atributos y métodos.
Aquí hay 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 en cualquier lugar
self._balance = balance # Protegido - uso interno
self.__account_id = account_id # Privado - solo 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 bienAcceder a 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 miembros privados (doble guion bajo - name mangling):
# Esto no funcionará:
# print(account.__account_id) # AttributeError
# Pero esto funciona (name mangling):
print(account._BankAccount__account_id) # 12345Crea una subclase para mostrar el acceso protegido frente al privado:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Protegido - accesible en la subclase
def show_id(self):
# return self.__account_id # Esto no funcionará - 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 privadoSalida:
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 utilizan un guion bajo simple (_) y solo deben utilizarse dentro de la jerarquía de clases. Los miembros privados utilizan un guion bajo doble (__) y se les aplica el "name-mangling" (ofuscación de nombres) para una mayor privacidad. El control de acceso de Python se basa en convenciones, no se aplica de forma 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 guían tu implementación
- Sigue los comentarios TODO en
bankaccount.pypara implementar la funcionalidad requerida - Implementa los niveles de acceso adecuados (público, protegido, privado) según lo especificado
- Asegúrate de que todos los métodos manejen los casos de borde de manera apropiada (depósitos negativos, etc.)
Hoja de referencia
Python tiene tres niveles de control de acceso para los miembros de una clase:
- Público: Sin prefijo, accesible desde cualquier lugar
- Protegido: Guion bajo simple (
_), para uso interno dentro de la jerarquía de clases - Privado: Guion bajo doble (
__), con "name-mangling" para acceso exclusivo de la clase
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Público
self._balance = balance # Protegido
self.__account_id = account_id # Privado
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._balanceAcceso a los miembros:
account = BankAccount("Alice", 1000, "12345")
# Acceso público
print(account.owner) # Funciona correctamente
# Acceso protegido (funciona pero no se recomienda)
print(account._balance) # 1500
# Acceso privado (con name mangling)
print(account._BankAccount__account_id) # 12345En subclases:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Protegido - accesible
def show_id(self):
# return self.__account_id # Privado - no accesible
return "Cannot access private member"Pruébalo tú mismo
from bank_account import BankAccount
# Manejador 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":
# Probando 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":
# Probando la 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":
# Probando el acceso a atributos privados
account = BankAccount("Alice Brown", "98765")
try:
print(account.__balance) # Esto lanzará un AttributeError
except AttributeError:
pass
try:
print(account.__account_number) # Esto lanzará un AttributeError
except AttributeError:
pass
print("Private attributes are not directly accessible")
account.deposit(500)
print(account.get_balance()) # Acceso a través de un método público
elif test_case == "name_mangling":
# Demostrando el "name mangling" para atributos privados
account = BankAccount("Charlie Green", "13579")
print(account._BankAccount__balance) # Accediendo a un atributo privado a través de "name mangling"
print(account._BankAccount__account_number) # Accediendo a un atributo privado a través de "name mangling"
account.deposit(300)
print(account._BankAccount__balance) # Debería mostrar el saldo actualizado
elif test_case == "multiple_accounts":
# Probando múltiples 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 Object Oriented Programming
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases vs ObjetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Resumen - Calculadora simple4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosResumen - 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 propertyDecorador de métodos estáticosDecorador de métodos de clase5Polimorfismo
Sobreescritura de métodos revisitadaDuck TypingClases y métodos abstractosDiseño de interfacesResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. 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 de claseDecoradores de propiedadesAtributos privadosResumen - Gestor de cuentas bancarias6Encapsulamiento
Miembros públicos, protegidos y privadosModificadores de accesoOcultamiento de informaciónDecoradores de propiedades avanzadosResumen - Sistema de registros de estudiantes