Médio Python

Conta com atributo de classe

Enunciado

Crie a classe Conta com um atributo de classe total_contas que conta quantas instâncias já foram criadas. Cada conta tem titular e saldo (atributos de instância). Adicione os métodos depositar(valor) e sacar(valor), sendo que sacar deve levantar ValueError("saldo insuficiente") se o valor for maior que o saldo. Imprima o total de contas criadas.

Requisitos

  • Conta.total_contas começa em 0 e é incrementado a cada nova instância.
  • depositar soma ao saldo; sacar subtrai, mas levanta ValueError se faltar saldo.
  • O programa cria duas contas e imprime Conta.total_contas.
  • A saída final contém o total igual a 2.

Código inicial

class Conta:
    total_contas = 0

    def __init__(self, titular, saldo=0.0):
        # incremente o contador de classe e guarde atributos de instância
        pass

    def depositar(self, valor):
        pass

    def sacar(self, valor):
        pass


c1 = Conta("Ana", 100.0)
c2 = Conta("Bruno")
c1.depositar(50)
c1.sacar(30)
print("Total de contas:", Conta.total_contas)
print("Saldo Ana:", c1.saldo)

Saída esperada

Total de contas: 2
Saldo Ana: 120.0
Ver dica

Para alterar o atributo de classe use Conta.total_contas += 1 (ou type(self).total_contas += 1). self.total_contas também funciona, mas cria um atributo de instância se você atribuir.

Mostrar solução
class Conta:
    # atributo de classe: pertence à classe, não à instância
    total_contas = 0

    def __init__(self, titular, saldo=0.0):
        self.titular = titular
        self.saldo = saldo
        # incrementa o contador compartilhado
        Conta.total_contas += 1

    def depositar(self, valor):
        if valor <= 0:
            raise ValueError("valor deve ser positivo")
        self.saldo += valor

    def sacar(self, valor):
        if valor > self.saldo:
            raise ValueError("saldo insuficiente")
        self.saldo -= valor


c1 = Conta("Ana", 100.0)
c2 = Conta("Bruno")
c1.depositar(50)
c1.sacar(30)
print("Total de contas:", Conta.total_contas)
print("Saldo Ana:", c1.saldo)

Passo a passo

  1. total_contas = 0 é definido no corpo da classe, então é um atributo de classe compartilhado.
  2. __init__ recebe titular e saldo e os guarda como atributos de instância com self.titular e self.saldo.
  3. A linha Conta.total_contas += 1 atualiza o atributo da classe, contando cada criação.
  4. depositar valida o valor e soma ao saldo do objeto atual (self.saldo).
  5. sacar verifica se há saldo suficiente; se não, levanta ValueError.
  6. Criamos c1 e c2; cada chamada a Conta(...) roda __init__ e incrementa o contador.
  7. c1.depositar(50) e c1.sacar(30) alteram apenas o saldo de c1.
  8. Imprimimos Conta.total_contas (2) e c1.saldo (120.0).

Por que funciona

Atributos de classe existem uma única vez e são acessados por Classe.atributo. Como __init__ roda em toda criação de objeto, incrementar Conta.total_contas ali garante a contagem correta. Já self.saldo é individual: alterar c1.saldo não afeta c2.saldo, exatamente o comportamento desejado.

Erros comuns

  • Escrever total_contas += 1 sem prefixo dentro de __init__ gera UnboundLocalError, pois o Python trata como variável local.
  • Usar self.total_contas += 1 cria um atributo de instância que sombreia o da classe; o contador da classe fica em 0 e a contagem quebra.
  • Em sacar, comparar valor > self.saldo antes de checar valores negativos pode aceitar saques negativos; valide entradas.

Outra forma de resolver

Use type(self).total_contas += 1 para funcionar também em subclasses:

type(self).total_contas += 1

Assim, se ContaEspecial(Conta) existir, o contador da subclasse é usado em vez do da classe base.

Saída esperada

Total de contas: 2
Saldo Ana: 120.0