"""
Sistema de contas bancarias

Uma conta abstrata (não deve ser instanciado)
Criar classe conta especializada (Conta poupança / conta universitaria)
"""
from abc import ABC, abstractmethod


class Conta(ABC):
    def __init__(self, agencia, conta, saldo):
        self._agencia = agencia
        self._conta = conta
        self._saldo = saldo

    @property
    def agencia(self):
        return self._agencia

    @property
    def conta(self):
        return self._conta

    @property
    def saldo(self):
        return self._saldo

    @saldo.setter
    def saldo(self, valor):
        # Verifica se valor é uma instancia de int ou float
        if not isinstance(valor, (int, float)):
            raise ValueError('Saldo precisa ser númerico!')

        self._saldo = valor

    def depositar(self, valor):
        if not isinstance(valor, (int, float)):
            raise ValueError('Valor do depósito precisa ser númerico!')

        self._saldo += valor
        self.detalhes()

    def detalhes(self):
        print(f'Agência: {self.agencia}', end=' ')
        print(f'Conta: {self.conta}', end=' ')
        print(f'Saldo: {self.saldo}')

    @abstractmethod
    def sacar(self, valor):
        """
        Método abstrato pois:
        Toda conta precisa do método sacar, entretanto o valor limite de saque
        pode ser diferente em outros tipos de conta. Por este motivo, este
        método será escrito nas classes filhas.
        """
        pass


class ContaPoupanca(Conta):
    def sacar(self, valor):
        if self.saldo < valor:
            print('Saldo insuficiente!')
            return

        self.saldo -= valor
        self.detalhes()


class ContaCorrente(Conta):
    def __init__(self, agencia, conta, saldo, limite=100):
        super().__init__(agencia, conta, saldo)
        self._limite = limite

    @property
    def limite(self):
        return self._limite

    def sacar(self, valor):
        if (self.saldo + self.limite) < valor:
            print('Saldo insuficiente!')
            return

        self.saldo -= valor
        self.detalhes()


cp = ContaPoupanca(1111, 2222, 0)
cp.depositar(10)
cp.sacar(5)
cp.sacar(5)
cp.sacar(1)

print('\n#####################################################\n')

cc = ContaCorrente(agencia=1111, conta=3333, saldo=0, limite=500)
cc.depositar(100)
cc.sacar(250)
cc.sacar(500)   # Saldo insuficiente
cc.depositar(1000)

"""
Sistema de contas bancarias

Uma conta abstrata (não deve ser instanciado)
Criar classe conta especializada (Conta poupança / conta universitaria)
"""
from abc import ABC, abstractmethod


class Conta(ABC):
    def __init__(self, agencia, conta, saldo):
        self._agencia = agencia
        self._conta = conta
        self._saldo = saldo

    @property
    def agencia(self):
        return self._agencia

    @property
    def conta(self):
        return self._conta

    @property
    def saldo(self):
        return self._saldo

    @saldo.setter
    def saldo(self, valor):
        # Verifica se valor é uma instancia de int ou float
        if not isinstance(valor, (int, float)):
            raise ValueError('Saldo precisa ser númerico!')

        self._saldo = valor

    def depositar(self, valor):
        if not isinstance(valor, (int, float)):
            raise ValueError('Valor do depósito precisa ser númerico!')

        self._saldo += valor
        self.detalhes()

    def detalhes(self):
        print(f'Agência: {self.agencia}', end=' ')
        print(f'Conta: {self.conta}', end=' ')
        print(f'Saldo: {self.saldo}')

    @abstractmethod
    def sacar(self, valor):
        """
        Método abstrato pois:
        Toda conta precisa do método sacar, entretanto o valor limite de saque
        pode ser diferente em outros tipos de conta. Por este motivo, este
        método será escrito nas classes filhas.
        """
        pass


class ContaPoupanca(Conta):
    def sacar(self, valor):
        if self.saldo < valor:
            print('Saldo insuficiente!')
            return

        self.saldo -= valor
        self.detalhes()


class ContaCorrente(Conta):
    def __init__(self, agencia, conta, saldo, limite=100):
        super().__init__(agencia, conta, saldo)
        self._limite = limite

    @property
    def limite(self):
        return self._limite

    def sacar(self, valor):
        if (self.saldo + self.limite) < valor:
            print('Saldo insuficiente!')
            return

        self.saldo -= valor
        self.detalhes()


cp = ContaPoupanca(1111, 2222, 0)
cp.depositar(10)
cp.sacar(5)
cp.sacar(5)
cp.sacar(1)

print('\n#####################################################\n')

cc = ContaCorrente(agencia=1111, conta=3333, saldo=0, limite=500)
cc.depositar(100)
cc.sacar(250)
cc.sacar(500)   # Saldo insuficiente
cc.depositar(1000)

Sistema de contas bancarias  Uma conta abstrata (não deve ser instanciado) Criar classe conta especializada (Conta poupança / conta universitaria) # Verifica se valor é uma instancia de int ou float Método abstrato pois:         Toda conta precisa do método sacar, entretanto o valor limite de saque         pode ser diferente em outros tipos de conta. Por este motivo, este         método será escrito nas classes filhas. #####################################################\n') # Saldo insuficiente