Python Intermediário POO na Prática: o Código e os Comandos que Realmente Contam

Python Intermediário POO: o essencial em um artigo — código real, diagramas e etapas concretas, extratos de um curso de 36 lições.

Python Intermediário POO na Prática: o Código e os Comandos que Realmente Contam

Sem teoria interminável aqui: abra o terminal e pratique. Aqui está o essencial de Python Intermediário POO, extraído diretamente de um curso completo de 36 lições — com código real que você pode copiar e colar agora.

tl;dr
  • Introdução e Instalação
  • Revisão de Python
  • Funções avançadas e lambdas
  • Classes e objetos
  • Herança e polimorfismo
~$ cat ./parcours.md # Python Intermediário POO — 10 capítulos
01
Introdução e Instalação
→ Apresentação do curso→ Instalar Python, VS Code e um ambiente virtual+ 1 mais lições
02
Revisão Python
→ Variáveis, tipos e estruturas de dados essenciais→ Condições, loops e compreensões de lista+ 1 mais lições
03
Funções avançadas e lambdas
→ Lambda, map, filter, reduce→ *args, **kwargs e argumentos padrão+ 1 mais lições
04
Classes e objetos
→ Por que a POO? Classes vs instâncias→ Definir uma classe: __init__, atributos e métodos+ 2 mais lições
05
Herança e polimorfismo
→ Herança simples→ Herança múltipla e MRO+ 1 mais lições
06
Métodos especiais dunder
→ __str__, __repr__, __len__→ Operadores sobrecarregados: __add__, __eq__, __lt__+ 1 mais lições
07
Módulos e pacotes
→ Import, módulos e namespaces→ Criar seu próprio pacote com __init__.py+ 1 mais lições
08
Gerenciamento de erros e exceções
→ try, except, else, finally→ Exceções personalizadas+ 1 mais lições
🏁
Projeto final (+ 2 capítulos no caminho)
→ Você sai com um projeto concreto e demonstrável

Encapsulamento, properties e setters

NOTEObjetivo — Aprender a proteger os atributos internos de um objeto e validar sua modificação graças às properties, sem sobrecarregar a interface pública.

Objetivos pedagógicos

TIPAo final deste módulo — Você saberá usar as convenções _x e __x, transformar um atributo em property para adicionar validação e saber quando fazer isso.

O que é encapsulamento?

O encapsulamento consiste em ocultar os detalhes internos de uma classe e expor apenas uma interface controlada.

NOTEAnalogia — Um controle remoto de TV: você pressiona "volume +" sem saber o que acontece nos circuitos. A interface é simples, o interno é protegido.

Convenções Python

Python não força a confidencialidade (ao contrário de Java). Ele usa convenções baseadas no nome.

ConvençãoSignificadoEfeito real
nomPúblicoAcesso livre, faz parte da API
_nomProtegido (convenção)"Não toque, a menos que saiba o que está fazendo"
__nomPrivado (name mangling)Renomeado para _NomClasse__nom
nom_Evita colisão com palavra-chaveEx: class_ em vez de class
output
class CompteBancaire:
    def __init__(self, titulaire, solde):
        self.titulaire = titulaire        # public
        self._solde = solde               # convention : ne pas toucher
        self.__pin = "1234"                # privé (name mangling)

c = CompteBancaire("Alice", 1000)
print(c.titulaire)                  # OK
print(c._solde)                     # accessible mais déconseillé
# print(c.__pin)                    # AttributeError !
print(c._CompteBancaire__pin)       # accessible avec le nom manglé
WARNINGO __ não é uma segurança — É um mecanismo para evitar colisões acidentais na herança. Para segurança real, use permissões no nível do sistema.

O problema sem encapsulamento

output
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

t = Temperature(25)
t.celsius = -500          # absurde !
print(t.celsius)          # -500

Nenhuma validação. O -500 é impossível (zero absoluto = -273.15), mas Python aceita.

@property : transformar um atributo em método

Um @property faz com que uma chamada como obj.attribut execute na verdade um método, sem alterar a sintaxe de uso.

output
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, valeur):
        if valeur < -273.15:
            raise ValueError("Sous le zéro absolu, impossible")
        self._celsius = valeur

t = Temperature(25)
print(t.celsius)            # 25 (appelle le getter)
t.celsius = 30              # appelle le setter, OK
t.celsius = -300            # ValueError !
TIPO superpoder — Você mantém a sintaxe t.celsius (simples), mas adiciona controle invisível. O código do usuário não precisa mudar nada.

Property somente leitura

Para um atributo calculado (derivado de outros) que não deve ser modificado diretamente.

output
class Cercle:
    def __init__(self, rayon):
        self.rayon = rayon

    @property
    def diametre(self):
        return self.rayon * 2

    @property
    def aire(self):
        from math import pi
        return pi * self.rayon ** 2

c = Cercle(5)
print(c.diametre)         # 10
print(c.aire)             # 78.539...
# c.aire = 100            # AttributeError : pas de setter

Property completa com getter, setter, deleter

output
class Personne:
    def __init__(self, nom):
        self._nom = nom

    @property
    def nom(self):
        return self._nom

    @nom.setter
    def nom(self, valeur):
        if not isinstance(valeur, str) or len(valeur) < 2:
            raise ValueError("Nom invalide")
        self._nom = valeur.title()      # normalisation

    @nom.deleter
    def nom(self):
        print("Suppression du nom")
        self._nom = None

p = Personne("alice")
print(p.nom)              # Alice (normalisé)
p.nom = "bob"
print(p.nom)              # Bob
del p.nom                 # Suppression du nom

Caso prático : CompteBancaire com validação

output
class CompteBancaire:
    def __init__(self, titulaire, solde=0):
        self.titulaire = titulaire
        self._solde = 0
        self.solde = solde         # passe par le setter !

    @property
    def solde(self):
        return self._solde

    @solde.setter
    def solde(self, valeur):
        if valeur < 0:
            raise ValueError("Solde négatif interdit")
        self._solde = valeur

    def deposer(self, montant):
        if montant <= 0:
            raise ValueError("Montant doit être positif")
        self.solde += montant       # passe par le setter

    def retirer(self, montant):
        if montant > self._solde:
            raise ValueError("Solde insuffisant")
        self.solde -= montant

c = CompteBancaire("Alice", 1000)
c.deposer(500)
print(c.solde)            # 1500
# c.solde = -100          # ValueError

Herança simples

NOTEObjetivo — Aprender a criar uma nova classe a partir de uma existente, reutilizando seu código e adaptando-o. É o mecanismo chave para evitar duplicação de código em POO.

Objetivos pedagógicos

TIPAo final deste módulo — Você saberá definir uma classe filha que herda de uma classe mãe, sobrescrever seus métodos e chamar a versão pai com super().

O conceito

A herança permite criar uma classe especializada a partir de uma classe geral. A classe filha recupera tudo o que a classe mãe oferece e depois adiciona ou modifica.

NOTEAnalogia — Um Cachorro é um Animal. Todo cachorro tem comportamentos de animal (comer, dormir), mais comportamentos específicos (latir). Dizemos que Chien é-um Animal.

Primeiro exemplo

output
class Animal:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age

    def manger(self):
        print(f"{self.nom} mange")

    def dormir(self):
        print(f"{self.nom} dort")


class Chien(Animal):
    def aboyer(self):
        print(f"{self.nom} : Wouaf !")


rex = Chien("Rex", 5)
rex.manger()              # hérité d'Animal
rex.dormir()              # hérité d'Animal
rex.aboyer()              # propre à Chien
print(rex.age)            # hérité

Chien não define __init__: Python usa automaticamente o de Animal.

Sobrescrever (override) um método

A classe filha pode redefinir um método da mãe para adaptar seu comportamento.

output
class Animal:
    def parler(self):
        print("Bruit générique d'animal")


class Chien(Animal):
    def parler(self):
        print("Wouaf !")


class Chat(Animal):
    def parler(self):
        print("Miaou")


for a in [Chien(), Chat(), Animal()]:
    a.parler()
# Wouaf !
# Miaou
# Bruit générique d'animal
TIPPolimorfismo — A mesma chamada a.parler() produz um resultado diferente dependendo da classe real de a. É um dos 4 pilares da POO.

super() : chamar o método pai

Ao sobrescrever um método, frequentemente queremos completar o comportamento pai em vez de substituí-lo.

output
class Animal:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age

    def description(self):
        return f"{self.nom}, {self.age} ans"


class Chien(Animal):
    def __init__(self, nom, age, race):
        super().__init__(nom, age)        # appelle Animal.__init__
        self.race = race

    def description(self):
        base = super().description()       # appelle Animal.description
        return f"{base}, race {self.race}"


rex = Chien("Rex", 5, "Labrador")
print(rex.description())     # Rex, 5 ans, race Labrador
WARNINGRegra — Assim que uma classe filha tem seu próprio __init__, você deve chamar super().__init__(...) para inicializar os atributos da mãe. Esquecer = bugs garantidos.

Verificar a parentela : isinstance e issubclass

output
rex = Chien("Rex", 5, "Labrador")

print(isinstance(rex, Chien))      # True
print(isinstance(rex, Animal))     # True (héritage)
print(isinstance(rex, Chat))       # False

print(issubclass(Chien, Animal))   # True
print(issubclass(Animal, Chien))   # False
TIPPythonic — Use isinstance(x, Animal) em vez de type(x) == Animal. A primeira forma respeita a herança.

Quando usar herança?

RelaçãoHerança?
Chien é-um AnimalSim
Roman é-um LivreSim
Voiture tem-um MoteurNão — composição
Bibliothèque contém LivresNão — composição
NOTERegra de ouro — Prefira a composição à herança. Se a relação não for uma verdadeira especialização, use um atributo em vez de herança.

Caso concreto : aplicação biblioteca

output
class Livre:
    def __init__(self, titre, auteur, isbn):
        self.titre = titre
        self.auteur = auteur
        self.isbn = isbn
        self.disponible = True

    def description(self):
        return f"{self.titre} de {self.auteur}"


class Roman(Livre):
    def __init__(self, titre, auteur, isbn, genre):
        super().__init__(titre, auteur, isbn)
        self.genre = genre

    def description(self):
        return f"{super().description()} -- roman {self.genre}"


class LivreNumerique(Livre):
    def __init__(self, titre, auteur, isbn, format_fichier):
        super().__init__(titre, auteur, isbn)
        self.format_fichier = format_fichier

    def telecharger(self):
        print(f"Téléchargement de {self.titre}.{self.format_fichier}")


dune = Roman("Dune", "Herbert", "978...", "science-fiction")
ebook = LivreNumerique("1984", "Orwell", "978...", "epub")

print(dune.description())       # Dune de Herbert -- roman science-fiction
print(ebook.description())       # 1984 de Orwell
ebook.telecharger()              # Téléchargement de 1984.epub

Hierarquias comuns em Python

Lambda, map, filter, reduce

NOTEObjetivo — Descobrir as funções anônimas (lambda) e as funções de ordem superior (map, filter, reduce), que permitem transformar e filtrar dados de forma muito concisa.

Objetivos pedagógicos

TIPAo final deste módulo — Você saberá quando usar uma lambda e escolher entre map/filter e uma list comprehension conforme o contexto.

O que é uma lambda?

Uma lambda é uma função anônima (sem nome) que cabe em uma única linha. É usada para operações curtas passadas como argumento para outra função.

Sintaxe

output
lambda parametres: expression

Comparação

output
def doubler(x):
    return x * 2

doubler_lambda = lambda x: x * 2

print(doubler(5))         # 10
print(doubler_lambda(5))  # 10
NOTEAnalogia — Um def clássico é como criar uma receita nomeada em um livro. Uma lambda é rabiscar uma receita em um post-it e entregá-la imediatamente a alguém.

Lambdas com múltiplos parâmetros

output
somme = lambda a, b: a + b
print(somme(3, 4))                       # 7

est_pair = lambda n: n % 2 == 0
print(est_pair(8))                       # True
WARNINGLimite — Uma lambda contém apenas uma única expressão. Sem return explícito, sem múltiplas linhas. Quando for mais complexo, use def.

map() : transformar cada elemento

map(fonction, iterable) aplica a função a cada elemento e retorna um iterador. Frequentemente envolve-se em list().

output
prix = [10, 25, 7, 50]
prix_ttc = list(map(lambda p: p * 1.20, prix))
print(prix_ttc)        # [12.0, 30.0, 8.4, 60.0]

mots = ["python", "poo", "code"]
majuscules = list(map(str.upper, mots))
print(majuscules)      # ['PYTHON', 'POO', 'CODE']

Com várias sequências

output
a = [1, 2, 3]
b = [10, 20, 30]
sommes = list(map(lambda x, y: x + y, a, b))
print(sommes)          # [11, 22, 33]

filter() : manter o que passa no teste

output
notes = [12, 8, 15, 6, 18, 11]
reussites = list(filter(lambda n: n >= 10, notes))
print(reussites)        # [12, 15, 18, 11]

mots = ["chat", "chien", "ours", "lion"]
courts = list(filter(lambda m: len(m) <= 4, mots))
print(courts)          # ['chat', 'ours', 'lion']
va-plus-loin

Este artigo cobre os trechos mais úteis — o curso completo Python Intermediário POO (11 capítulos, 36 lições, exercícios corrigidos e projeto final) leva você até o fim.

./acceder-au-cours-complet curso gratuito : Dominando Claude Code

FAQ

Quanto tempo para aprender Python Intermediário POO?
Com uma progressão estruturada (11 capítulos, 36 lições curtas e práticas), você atinge um nível operacional em algumas semanas dedicando 30 a 60 minutos por dia. O importante é praticar cada conceito imediatamente.
É preciso pré-requisitos?
Básicos de informática são suficientes. Se você sabe usar um terminal e ler código simples, está pronto.
Por onde começar concretamente?
Reproduza os comandos deste artigo e depois siga o curso completo Python Intermediário POO: ele encadeia as 36 lições em ordem, com exercícios e projeto final.

📬 Quer receber este tipo de guia toda semana? Inscreva-se gratuitamente — código real, zero enrolação.