Um dos exemplos clássicos e intuitivos para exemplificar o uso de classes simples é a implementação de uma versão simplificada de uma classe ContaCorrente.
a) codifique uma classe ContaCorrente, inicializada com um código, um saldo inicial e um limite.
b) implemente os métodos sacar(valor) e depositar(valor), com o cuidado especial de não permitir sacar valores que resultariam na extrapolação do limite da conta.
c) modifique a implementação para que todas operações sejam registradas. Então, forneça um método ver_extrato() que retorna uma lista com as operações realizadas.
d) adicione um método salvar_extrato (arquivo) que recebe um nome de um arquivo e salva o registro de operações nele.

Passo 1

O enunciado pede quatro coisas relacionadas a uma implementação simples de uma classe de conta corrente. Vou listar exatamente o que cada item exige e as informações que temos:
  • (a) Criar uma classe chamada ContaCorrente, que seja inicializada com:
    • um código (identificador da conta),
    • um saldo inicial,
    • um limite (limite de cheque especial).
  • (b) Implementar métodos:
    • sacar(valor) — deve realizar saque, mas NÃO permitir que o saque exceda o saldo mais o limite.
    • depositar(valor) — deve aumentar o saldo.
  • (c) Registrar todas as operações realizadas (saque e depósito) e fornecer um método ver_extrato() que retorne a lista com essas operações.
  • (d) Adicionar um método salvar_extrato(arquivo) que recebe o nome de um arquivo e salva o registro de operações nele.
Informações relevantes dadas:
  • Precisamos garantir a checagem do limite ao sacar.
  • O extrato deve armazenar cada operação (tipo e valores) para ser consultado e salvo.
  • Não foi especificado o formato exato do registro, então posso escolher um formato razoável e bem explicado.

Passo 2

Vamos começar pela estrutura básica de uma classe em Python (isso vale como “aula rápida” sobre classes):
  • Uma classe é definida com class Nome:.
  • O método especial __init__(self, ...) é o construtor: é chamado quando criamos um objeto e serve para inicializar os atributos.
  • Atributos (variáveis do objeto) são criados atribuindo self.atributo = valor.
  • Métodos são funções definidas dentro da classe que recebem self como primeiro argumento para acessar os atributos do objeto.
Implementação inicial (resposta ao item a): uma classe ContaCorrente com codigo, saldo e limite. Vou também inicializar o registro de operações como uma lista vazia — isso já prepara para o item (c).
Exemplo de código para essa etapa:
class ContaCorrente:
    def __init__(self, codigo, saldo_inicial=0.0, limite=0.0):
        """
        Inicializa a conta.
        codigo: identificador da conta (string ou int)
        saldo_inicial: saldo inicial (float)
        limite: limite de cheque especial (float)
        """
        self.codigo = codigo
        self.saldo = float(saldo_inicial)
        self.limite = float(limite)
        # Lista para registrar operações (cada entrada será um dicionário)
        self._extrato = []
Explicação das escolhas:
  • Converti saldo_inicial e limite para float para garantir operações numéricas consistentes.
  • _extrato com underscore para indicar que é “interno” (convenção), mas ainda acessível por métodos públicos.

Passo 3

Agora implementamos os métodos depositar e sacar (item b). Primeiro a lógica que precisamos entender e aplicar:
  • Depositando:
    • O valor deve ser positivo; se for inválido, não alteramos o saldo.
    • Ao depositar, o saldo aumenta.
    • Registramos a operação no extrato.
  • Sacando:
    • Definimos o “disponível” como saldo + limite. Isso é o máximo que pode ser usado.
    • Antes de permitir o saque, verificamos se valor <= disponível.
    • Se sim: subtrair do saldo e registrar a operação.
    • Se não: não permitir o saque (retornar False ou lançar erro). Vou optar por fazer o método retornar True se teve sucesso e False se falhou — isso é prático para código em prova e evita ter que tratar exceções.
Vou mostrar passo a passo os cálculos (a “aula” sobre esse ponto):
  • Disponível = saldo atual + limite.
  • Condição para permitir saque: valor <= disponível.
  • Atualização do saldo: self.saldo -= valor (se permitido).
Código para estes métodos:
    def depositar(self, valor):
        """Deposita um valor positivo. Retorna True se sucesso, False se valor inválido."""
        valor = float(valor)
        if valor <= 0:
            return False
        saldo_antes = self.saldo
        self.saldo += valor
        saldo_depois = self.saldo
        # Registrar no extrato (vou padronizar o formato no Passo 4)
        self._extrato.append({
            "tipo": "deposito",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True

    def sacar(self, valor):
        """Tenta sacar. Retorna True se sucesso, False se insuficiente ou valor inválido."""
        valor = float(valor)
        if valor <= 0:
            return False
        disponivel = self.saldo + self.limite
        if valor > disponivel:
            # Não permite extrapolar o limite
            return False
        saldo_antes = self.saldo
        self.saldo -= valor
        saldo_depois = self.saldo
        self._extrato.append({
            "tipo": "saque",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True
Observações didáticas:
  • Usei float(valor) para evitar problemas se o usuário passar um inteiro; em prova, isso demonstra cuidado com tipos.
  • Retornar booleano facilita testes rápidos: if conta.sacar(100): ... else: ....

Passo 4

Agora formalizamos o formato do extrato (item c) e implementamos ver_extrato().
Decisões de formato (claras e fáceis de ler):
  • Cada entrada do extrato será um dicionário com chaves:
    • "tipo": "deposito" ou "saque".
    • "valor": valor da operação (float).
    • "saldo_antes": saldo antes da operação (float).
    • "saldo_depois": saldo depois da operação (float).
    • Opcionalmente poderíamos adicionar "descricao" ou "data", mas o enunciado não exige; se quiser, posso incluir timestamp mais tarde.
Implementação de ver_extrato():
  • Deve retornar a lista de operações. Para segurança, retornamos uma cópia superficial (list(self._extrato)) para que o usuário não modifique diretamente o registro interno sem querer.
Código:
    def ver_extrato(self):
        """Retorna uma cópia da lista de operações (extrato)."""
        return list(self._extrato)
Exemplo de uso e interpretação:
  • Se eu fizer conta.depositar(200) e depois conta.sacar(50), o ver_extrato() poderá retornar algo como:
    • [{"tipo": "deposito", "valor": 200.0, "saldo_antes": 0.0, "saldo_depois": 200.0}, {"tipo": "saque", "valor": 50.0, "saldo_antes": 200.0, "saldo_depois": 150.0}]
  • Isso facilita mostrar extratos na tela ou salvar em arquivo.

Passo 5

Agora implementamos salvar_extrato(arquivo) (item d). O método vai receber uma string com o nome do arquivo (p.ex. "extrato.txt") e gravar uma representação legível do extrato nele. Cuidados:
  • Usar with open(arquivo, "w", encoding="utf-8") para garantir fechamento do arquivo.
  • Formatar cada entrada de forma legível — por exemplo: TIPO: depósito | VALOR: 100,00 | SALDO ANTES: 50,00 | SALDO DEPOIS: 150,00
  • Tratar possíveis exceções de I/O? Em prova, basta documentar que erros podem propagar; posso optar por capturar e retornar False em caso de erro e True se gravou com sucesso.
Implementação:
    def salvar_extrato(self, arquivo):
        """
        Salva o extrato em um arquivo texto.
        Retorna True se sucesso, False se ocorreu erro de escrita.
        """
        try:
            with open(arquivo, "w", encoding="utf-8") as f:
                f.write(f"Extrato da conta: {self.codigo}\n")
                f.write(f"Saldo atual: {self.saldo}\n")
                f.write(f"Limite: {self.limite}\n")
                f.write("-" * 40 + "\n")
                for op in self._extrato:
                    linha = (
                        f"{op['tipo'].upper():8} | "
                        f"VALOR: {op['valor']:,.2f} | "
                        f"ANTES: {op['saldo_antes']:,.2f} | "
                        f"DEPOIS: {op['saldo_depois']:,.2f}\n"
                    )
                    f.write(linha)
            return True
        except Exception:
            return False
Explicação didática:
  • Usei formatação com :,.2f para duas casas decimais e separador de milhar (apenas para saída legível).
  • O bloco try/except evita que a função lance uma exceção para quem apenas quer saber se salvou com sucesso.

Passo 6

Juntando tudo: abaixo está a classe completa com todos os métodos implementados, docstrings e comportamento explicado. Também incluí (comentado) um pequeno exemplo de uso que ajuda a testar a classe rapidamente.
Código final (pronto para usar em uma prova ou exercício prático):
class ContaCorrente:
    def __init__(self, codigo, saldo_inicial=0.0, limite=0.0):
        """
        Inicializa a conta.
        codigo: identificador da conta (string ou int)
        saldo_inicial: saldo inicial (float)
        limite: limite de cheque especial (float)
        """
        self.codigo = codigo
        self.saldo = float(saldo_inicial)
        self.limite = float(limite)
        # Lista para registrar operações (cada entrada será um dicionário)
        self._extrato = []

    def depositar(self, valor):
        """Deposita um valor positivo. Retorna True se sucesso, False se valor inválido."""
        try:
            valor = float(valor)
        except (TypeError, ValueError):
            return False
        if valor <= 0:
            return False
        saldo_antes = self.saldo
        self.saldo += valor
        saldo_depois = self.saldo
        # Registrar no extrato
        self._extrato.append({
            "tipo": "deposito",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True

    def sacar(self, valor):
        """Tenta sacar. Retorna True se sucesso, False se insuficiente ou valor inválido."""
        try:
            valor = float(valor)
        except (TypeError, ValueError):
            return False
        if valor <= 0:
            return False
        disponivel = self.saldo + self.limite
        if valor > disponivel:
            # Não permite extrapolar o limite
            return False
        saldo_antes = self.saldo
        self.saldo -= valor
        saldo_depois = self.saldo
        self._extrato.append({
            "tipo": "saque",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True

    def ver_extrato(self):
        """Retorna uma cópia da lista de operações (extrato)."""
        return list(self._extrato)

    def salvar_extrato(self, arquivo):
        """
        Salva o extrato em um arquivo texto.
        Retorna True se sucesso, False se ocorreu erro de escrita.
        """
        try:
            with open(arquivo, "w", encoding="utf-8") as f:
                f.write(f"Extrato da conta: {self.codigo}\n")
                f.write(f"Saldo atual: {self.saldo}\n")
                f.write(f"Limite: {self.limite}\n")
                f.write("-" * 40 + "\n")
                for op in self._extrato:
                    linha = (
                        f"{op['tipo'].upper():8} | "
                        f"VALOR: {op['valor']:,.2f} | "
                        f"ANTES: {op['saldo_antes']:,.2f} | "
                        f"DEPOIS: {op['saldo_depois']:,.2f}\n"
                    )
                    f.write(linha)
            return True
        except Exception:
            return False

# Exemplo de uso (pode descomentar para testar):
# conta = ContaCorrente("123-4", saldo_inicial=100.0, limite=50.0)
# conta.depositar(50)
# sucesso = conta.sacar(160)  # deve ser False, pois 160 > 100+50
# sucesso2 = conta.sacar(120) # deve ser True: saldo 150 -> após saque saldo = 30
# print(conta.ver_extrato())
# conta.salvar_extrato("meu_extrato.txt")

Resposta

class ContaCorrente:
    def __init__(self, codigo, saldo_inicial=0.0, limite=0.0):
        """
        Inicializa a conta.
        codigo: identificador da conta (string ou int)
        saldo_inicial: saldo inicial (float)
        limite: limite de cheque especial (float)
        """
        self.codigo = codigo
        self.saldo = float(saldo_inicial)
        self.limite = float(limite)
        # Lista para registrar operações (cada entrada será um dicionário)
        self._extrato = []

    def depositar(self, valor):
        """Deposita um valor positivo. Retorna True se sucesso, False se valor inválido."""
        try:
            valor = float(valor)
        except (TypeError, ValueError):
            return False
        if valor <= 0:
            return False
        saldo_antes = self.saldo
        self.saldo += valor
        saldo_depois = self.saldo
        # Registrar no extrato
        self._extrato.append({
            "tipo": "deposito",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True

    def sacar(self, valor):
        """Tenta sacar. Retorna True se sucesso, False se insuficiente ou valor inválido."""
        try:
            valor = float(valor)
        except (TypeError, ValueError):
            return False
        if valor <= 0:
            return False
        disponivel = self.saldo + self.limite
        if valor > disponivel:
            # Não permite extrapolar o limite
            return False
        saldo_antes = self.saldo
        self.saldo -= valor
        saldo_depois = self.saldo
        self._extrato.append({
            "tipo": "saque",
            "valor": valor,
            "saldo_antes": saldo_antes,
            "saldo_depois": saldo_depois
        })
        return True

    def ver_extrato(self):
        """Retorna uma cópia da lista de operações (extrato)."""
        return list(self._extrato)

    def salvar_extrato(self, arquivo):
        """
        Salva o extrato em um arquivo texto.
        Retorna True se sucesso, False se ocorreu erro de escrita.
        """
        try:
            with open(arquivo, "w", encoding="utf-8") as f:
                f.write(f"Extrato da conta: {self.codigo}\n")
                f.write(f"Saldo atual: {self.saldo}\n")
                f.write(f"Limite: {self.limite}\n")
                f.write("-" * 40 + "\n")
                for op in self._extrato:
                    linha = (
                        f"{op['tipo'].upper():8} | "
                        f"VALOR: {op['valor']:,.2f} | "
                        f"ANTES: {op['saldo_antes']:,.2f} | "
                        f"DEPOIS: {op['saldo_depois']:,.2f}\n"
                    )
                    f.write(linha)
            return True
        except Exception:
            return False

Exercícios relacionados