Programação Orientada a Objetos: Conceitos e Aplicações Práticas em Python 🐍 Etapa 10

 Seja muito bem-vindo à Academy Code Christ!


🌍 Academy Code Christ está disponível em vários idiomas.
Fique à vontade para usar o tradutor na Barra lateral (Sidebar) e aprender no seu idioma.

Python 🐍 Etapa 10
Programação Orientada a Objetos



📚 Continue sua jornada de aprendizado


A Academy Code Christ oferece trilhas de aprendizado em diferentes tecnologias. Explore os cursos, acompanhe as aulas e avance em sua jornada de conhecimento acessando os menus correspondentes:



💻 Pratique o que você aprende


🎯 Por que aprender Programação Orientada a Objetos?

Até agora, você escreveu código de maneira estruturada: criou funções, manipulou dados, agrupou em módulos. 

Mas conforme o projeto cresce, isso começa a ficar complicado de gerenciar — especialmente se muitas variáveis e funções dependem umas das outras.

A Programação Orientada a Objetos ajuda a organizar o código de forma natural, semelhante ao mundo real. 

Exemplo: você pode representar um aluno, um carro ou uma conta bancária — cada um com seus atributos (dados) e métodos (ações).

Isso traz grandes vantagens:

●     🔹 Reutilização de código (herança, classes genéricas)

●     🔹 Organização e clareza

●     🔹 Facilidade de manutenção e expansão

●     🔹 Representação intuitiva de entidades reais


Conceitos básicos

Conceito

Descrição


Classe

É o modelo ou a forma que define as características e comportamentos de um objeto.

Objeto

É uma instância (exemplo concreto) de uma classe.

Atributos

São as variáveis que pertencem a uma classe/objeto (características).

Métodos

São funções definidas dentro da classe (comportamentos).

Encapsulamento

Técnica que protege os dados internos de uma classe.

Herança

Permite que uma classe “filha” herde atributos e métodos de uma “classe pai”.

Polimorfismo

Permite que métodos com o mesmo nome tenham comportamentos diferentes.

Vamos ver cada um desses conceitos na prática.


Criando sua primeira classe

class Pessoa:

    def __init__(self, nome, idade):

        self.nome = nome

        self.idade = idade

 

    def apresentar(self):

        print(f"Olá! Meu nome é {self.nome} e tenho {self.idade} anos.")

 

Como funciona:

●     class Pessoa: → cria uma nova classe chamada Pessoa.

●     __init__ → é o método construtor, executado automaticamente ao criar um novo objeto.

●     self → é uma referência ao próprio objeto.

●     Os parâmetros (nome, idade) são recebidos e armazenados como atributos.


Criando objetos (instâncias):

p1 = Pessoa("Ana", 25)

p2 = Pessoa("Bruno", 30)

 

p1.apresentar()

p2.apresentar()

 

Saída:

Olá! Meu nome é Ana e tenho 25 anos.

Olá! Meu nome é Bruno e tenho 30 anos.

 


Entendendo self


O self é uma palavra obrigatória em métodos de classe e representa a própria instância.
 É o elo entre os atributos e os métodos do objeto.

class Carro:

    def __init__(self, modelo):

        self.modelo = modelo

 

    def mostrar_modelo(self):

        print("O modelo do carro é:", self.modelo)

 

Cada objeto armazena seus próprios dados e acessa-os com self.


Atributos de instância e de classe


Nem todos os atributos precisam ser únicos por objeto.
 Podemos ter variáveis que pertencem à classe toda.

class Aluno:

    escola = "Python Academy"  # atributo da classe

 

    def __init__(self, nome):

        self.nome = nome       # atributo da instância

 

a1 = Aluno("Carla")

a2 = Aluno("Lucas")

 

print(a1.nome, "-", a1.escola)

print(a2.nome, "-", a2.escola)

 

Saída:

Carla - Python Academy

Lucas - Python Academy

 

Se mudar Aluno.escola, o valor é alterado para todos.


Métodos de instância, classe e estáticos


1️⃣ Método de instância: age sobre o próprio objeto.

def metodo(self): ...

 

2️⃣ Método de classe: age sobre a classe inteira, e não sobre um objeto específico. É definido com @classmethod.

class Empresa:

    funcionarios = 0

 

    @classmethod

    def contratar(cls):

        cls.funcionarios += 1

 

3️⃣ Método estático: é uma função dentro da classe, que não acessa o estado da classe nem do objeto. Usa o decorador @staticmethod.

class Matematica:

    @staticmethod

    def dobro(x):

        return x * 2

 

print(Matematica.dobro(5))

 

Saída:

10

 

Encapsulamento: protegendo dados


Encapsular significa ocultar os detalhes internos do objeto, expondo apenas o necessário.

Níveis de acesso:


Prefixo

Nome exemplo

Descrição

Público

self.nome

acessível de qualquer lugar

Protegido

self._idade

convenção: acesso restrito a subclasses

Privado

self.__senha

acesso apenas dentro da própria classe

Exemplo:

class ContaBancaria:

    def __init__(self, titular, saldo):

        self.titular = titular

        self.__saldo = saldo  # privado

 

    def depositar(self, valor):

        self.__saldo += valor

 

    def exibir_saldo(self):

        print(f"Saldo atual: R${self.__saldo}")

 

conta = ContaBancaria("Ana", 500)

conta.depositar(200)

conta.exibir_saldo()

 

Saída:

Saldo atual: R$700

 

Qualquer tentativa de acessar conta.__saldo gerará erro — o dado está protegido.


Usando getters e setters


Para acessar ou alterar atributos privados de forma controlada, usamos métodos:

class Produto:

    def __init__(self, nome, preco):

        self.__nome = nome

        self.__preco = preco

 

    def get_preco(self):

        return self.__preco

 

    def set_preco(self, novo_preco):

        if novo_preco >= 0:

            self.__preco = novo_preco

        else:

            print("Erro: preço inválido.")

 

p = Produto("Camiseta", 50)

print(p.get_preco())

p.set_preco(-10)

 

Herança: reaproveitando código


A herança permite que uma classe filha herde atributos e métodos de uma classe pai.

class Pessoa:

    def __init__(self, nome):

        self.nome = nome

    def falar(self):

        print(f"{self.nome} está falando...")

 

class Estudante(Pessoa):

    def estudar(self):

        print(f"{self.nome} está estudando.")

 

e = Estudante("Lucas")

e.falar()

e.estudar()

 

Saída:

Lucas está falando...

Lucas está estudando.

 

A classe filha (Estudante) herda tudo que existe na classe Pessoa, podendo adicionar novos comportamentos.


Usando super() para aproveitar o construtor da classe pai


Quando a classe filha redefine o __init__, podemos chamar o construtor da classe pai com super().

class Funcionario(Pessoa):

    def __init__(self, nome, salario):

        super().__init__(nome)   # chama o construtor da classe Pessoa

        self.salario = salario

 

    def exibir_dados(self):

        print(f"{self.nome} ganha R${self.salario}")

 

f = Funcionario("Maria", 3500)

f.exibir_dados()


Comportamento polimórfico


Polimorfismo significa “múltiplas formas” — ou seja, diferentes classes podem ter métodos com o mesmo nome, mas comportamentos distintos.

class Animal:

    def som(self):

        print("Som genérico de animal")

 

class Cachorro(Animal):

    def som(self):

        print("Au Au!")

 

class Gato(Animal):

    def som(self):

        print("Miau!")

 

animais = [Cachorro(), Gato(), Animal()]

for a in animais:

    a.som()

 

Saída:

Au Au!

Miau!

Som genérico de animal

 

Cada objeto responde de forma diferente ao mesmo método — isso é polimorfismo em ação.


Classes abstratas


Classes que servem apenas como modelo para outras.
 Usamos o módulo abc (Abstract Base Class).

from abc import ABC, abstractmethod

 

class Forma(ABC):

    @abstractmethod

    def area(self):

        pass

 

Agora, qualquer classe filha precisa obrigatoriamente implementar area():

class Quadrado(Forma):

    def __init__(self, lado):

        self.lado = lado

    def area(self):

        return self.lado ** 2

 

q = Quadrado(4)

print(q.area())  # 16

 

Tentar instanciar Forma() diretamente dá erro — é uma classe abstrata.


Composição: “tem um”


Enquanto a herança representa um “é um”, a composição representa um “tem um”.

class Motor:

    def __init__(self, potencia):

        self.potencia = potencia

 

class Carro:

    def __init__(self, modelo, potencia):

        self.modelo = modelo

        self.motor = Motor(potencia)  # carro TEM um motor

 

c = Carro("Sedan", 120)

print(f"O carro {c.modelo} tem motor de {c.motor.potencia}cv.")

 

Saída:

O carro Sedan tem motor de 120cv.

 


Reescrevendo representações: __str__ e __repr__


Esses métodos especiais definem como um objeto aparece ao ser impresso.

class Pessoa:

    def __init__(self, nome, idade):

        self.nome = nome

        self.idade = idade

    def __str__(self):

        return f"{self.nome}, {self.idade} anos"

 

p = Pessoa("Ana", 28)

print(p)

 

Saída:

Ana, 28 anos

 


Mini‑projeto prático: Sistema de cadastro e conta bancária


class Pessoa:

    def __init__(self, nome, cpf):

        self.nome = nome

        self.cpf = cpf

 

class Conta:

    def __init__(self, titular, saldo=0):

        self.titular = titular

        self.__saldo = saldo

 

    def depositar(self, valor):

        if valor > 0:

            self.__saldo += valor

            print(f"Depósito de R${valor} realizado.")

        else:

            print("Valor inválido.")

 

    def sacar(self, valor):

        if 0 < valor <= self.__saldo:

            self.__saldo -= valor

            print(f"Saque de R${valor} concluído.")

        else:

            print("Saldo insuficiente.")

 

    def extrato(self):

        print(f"Titular: {self.titular.nome} | Saldo: R${self.__saldo}")

 

# Criando cliente e conta

cliente1 = Pessoa("Lucas", "123.456.789-00")

conta1 = Conta(cliente1, 1000)

 

conta1.depositar(250)

conta1.sacar(500)

conta1.extrato()

 

Saída:

Depósito de R$250 realizado.

Saque de R$500 concluído.

Titular: Lucas | Saldo: R$750

 

Esse código aplica encapsulamento, composição, métodos, atributos e instâncias reais. Tudo o que torna um sistema realista e orientado a objetos.


Boas práticas em POO


 🔹 Nomeie classes com letra maiúscula (ex: Cliente, Produto).
 🔹 Deixe cada classe com uma responsabilidade clara.
 🔹 Prefira herança apenas quando houver relação direta entre classes — do contrário, use composição.
 🔹 Use encapsulamento e propriedades para proteger dados.
 🔹 Documente suas classes com docstrings explicando o propósito e os métodos.
 🔹 Abuse da reutilização e evite repetição de código (Don’t Repeat Yourself – DRY).


Resumo do capítulo

Nesta etapa, você aprendeu a:

 ✅ Criar e instanciar classes e objetos.
 ✅ Definir
atributos e métodos próprios.
 ✅ Entender
encapsulamento, getters, setters e diferentes níveis de acesso.
 ✅ Aplicar
herança, super, polimorfismo e composição.
 ✅ Utilizar classes
abstratas, métodos especiais e boas práticas.
 ✅ Construir um sistema completo seguindo o paradigma orientado a objetos.

A partir de agora, você tem em mãos todo o poder da POO em Python — o mesmo estilo usado em frameworks e sistemas profissionais.


🎯 Na próxima etapa, entraremos no mundo da manipulação de arquivos e dados externos — onde você vai aprender a ler, gravar e processar informações armazenadas em disco, interagindo com o ambiente real.



Este conteúdo faz parte do Academy Code Christ. 

Um projeto criado para ajudar jovens e iniciantes a aprender programação do zero, de forma simples e gratuita.

Nossa missão é compartilhar conhecimento e incentivar mais pessoas a descobrir que também podem aprender tecnologia, criar projetos e desenvolver novas habilidades.
Todo o conteúdo é disponibilizado gratuitamente, de forma clara, prática e 
sem enrolação. 

Você pode apoiar o projeto se quiser 
com um café. 



Post a Comment

Postagem Anterior Próxima Postagem