Menu
Coddy logo textTech

Membros Públicos, Protegidos e Privados

Parte da seção Object Oriented Programming do Journey de Python da Coddy — lição 28 de 64.

O Python possui três níveis de controle de acesso para membros de classe: public, protected e private. Estes controlam como atributos e métodos podem ser acessados.

Aqui está um exemplo de uma classe com todos os três níveis de acesso:

class BankAccount:
    def __init__(self, owner, balance, account_id):
        self.owner = owner           # Público - acessível em qualquer lugar
        self._balance = balance      # Protegido - uso interno
        self.__account_id = account_id  # Privado - apenas para a classe
    
    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._balance

Acesse membros públicos de qualquer lugar:

account = BankAccount("Alice", 1000, "12345")
print(account.owner)        # Alice
account.deposit(500)        # Funciona perfeitamente

Acesse membros protegidos (sublinhado simples - apenas convenção):

print(account._balance)     # 1500 - funciona, mas não é recomendado
result = account._calculate_interest()  # Funciona, mas não é recomendado
print(result)               # 30.0

Tente acessar membros privados (sublinhado duplo - name mangling):

# Isso não funcionará:
# print(account.__account_id)  # AttributeError

# Mas isso funciona (name mangling):
print(account._BankAccount__account_id)  # 12345

Crie uma subclasse para mostrar o acesso protegido vs privado:

class SavingsAccount(BankAccount):
    def show_balance(self):
        return self._balance        # Protegido - acessível na subclasse
    
    def show_id(self):
        # return self.__account_id  # Isso não funcionará - privado
        return "Cannot access private member"
savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance())  # 2000
print(savings.show_id())       # Não é possível acessar o membro privado

Saída:

Alice
30.0
12345
2000
Cannot access private member

Ponto Chave: Membros públicos não possuem prefixo e são acessíveis em qualquer lugar. Membros protegidos usam um sublinhado simples (_) e devem ser usados apenas dentro da hierarquia de classes. Membros privados usam sublinhado duplo (__) e passam por name-mangling para uma privacidade mais forte. O controle de acesso do Python é baseado em convenções, não sendo estritamente imposto.

challenge icon

Desafio

Médio

Neste desafio, você implementará uma classe BankAccount que demonstra o uso adequado dos níveis de acesso público, protegido e privado em Python.

  • bankaccount.py - Contém a definição da classe com comentários TODO guiando sua implementação
  1. Siga os comentários TODO em bankaccount.py para implementar a funcionalidade exigida
  2. Implemente os níveis de acesso adequados (público, protegido, privado) conforme especificado
  3. Certifique-se de que todos os métodos tratem casos extremos adequadamente (depósitos negativos, etc.)

Folha de consulta

O Python possui três níveis de controle de acesso para membros de classe:

  • Público: Sem prefixo, acessível em qualquer lugar
  • Protegido: Sublinhado único (_), uso interno dentro da hierarquia de classes
  • Privado: Sublinhado duplo (__), com name-mangling para acesso exclusivo à classe
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._balance

Acessando membros:

account = BankAccount("Alice", 1000, "12345")

# Acesso público
print(account.owner)        # Funciona normalmente

# Acesso protegido (funciona, mas não é recomendado)
print(account._balance)     # 1500

# Acesso privado (com name mangling)
print(account._BankAccount__account_id)  # 12345

Em subclasses:

class SavingsAccount(BankAccount):
    def show_balance(self):
        return self._balance        # Protegido - acessível
    
    def show_id(self):
        # return self.__account_id  # Privado - não acessível
        return "Cannot access private member"

Experimente você mesmo

from bank_account import BankAccount

# Manipulador abrangente de casos de teste
test_case = input()

if test_case == "basic_test":
    # Teste de funcionalidade 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":
    # Testando 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":
    # Testando validação no método deposit
    account = BankAccount("Bob Johnson", "54321")
    print(account.deposit(-50))  # Deve retornar None
    print(account.deposit(0))    # Deve retornar None
    print(account.deposit(75))   # Deve retornar 75
    print(account.get_balance())

elif test_case == "private_access":
    # Testando acesso a atributo privado
    account = BankAccount("Alice Brown", "98765")
    try:
        print(account.__balance)  # Isso lançará um AttributeError
    except AttributeError:
        pass
    
    try:
        print(account.__account_number)  # Isso lançará um AttributeError
    except AttributeError:
        pass
    
    print("Private attributes are not directly accessible")
    account.deposit(500)
    print(account.get_balance())  # Acesso através de método público

elif test_case == "name_mangling":
    # Demonstrando name mangling para atributos privados
    account = BankAccount("Charlie Green", "13579")
    print(account._BankAccount__balance)        # Acessando atributo privado através de name mangling
    print(account._BankAccount__account_number)  # Acessando atributo privado através de name mangling
    account.deposit(300)
    print(account._BankAccount__balance)  # Deve mostrar o saldo atualizado

elif test_case == "multiple_accounts":
    # Testando múltiplas contas
    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":
    # Teste de desempenho com muitas transações
    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}")
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming