Classes e Objetos no Python: POO, __init__, self e dataclass

Cansado de programar?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Projetos práticos

Projetos práticos voltados para o mercado de trabalho

Prática profissional

Formação moderna com foco na prática profissional

Download do Artigo

✅ Artigo atualizado em Setembro 2026 (Python 3.13) Nova resposta rápida, seções sobre self, dataclasses e os 4 pilares da POO, tabela de decisão, erros comuns com traceback e 8 exercícios resolvidos. O exemplo de herança foi corrigido.

Resposta rápida

Uma classe é o molde que define atributos (dados) e métodos (comportamentos); um objeto é uma instância criada a partir desse molde. Em Python, você cria a classe com class Nome:, inicializa os atributos no __init__(self, ...) e cria o objeto chamando Nome(...).

1
2
3
4
5
6
7
8
9
class Pessoa:
    def __init__(self, nome):
        self.nome = nome

    def saudar(self):
        return f"Olá, eu sou {self.nome}"

ana = Pessoa("Ana")   # objeto (instância)
print(ana.saudar())   # Olá, eu sou Ana

Resumo em 30 segundos:

  • Classe = molde; objeto = instância. Pessoa é a classe, Pessoa("Ana") cria um objeto.
  • __init__ é executado automaticamente ao criar o objeto e inicializa os atributos (o “construtor”).
  • self é o próprio objeto: o Python o passa sozinho como primeiro argumento dos métodos.
  • Atributo de classe é compartilhado por todos os objetos; atributo de instância (self.x) é de cada objeto.
  • @dataclass gera __init__, __repr__ e __eq__ automaticamente.

Salve salve Pythonista!

Classes são moldes para criar objetos com atributos (dados) e métodos (comportamentos). São a base da Programação Orientada a Objetos (POO)!

Neste guia, você vai aprender:

  • ✅ Declarar classes e instanciar objetos
  • ✅ O que é self e como o __init__ funciona
  • ✅ Métodos especiais - init, str, repr
  • ✅ Tipos de métodos - instância, classe, estáticos
  • ✅ Dataclasses e os 4 pilares da POO
  • ✅ Casos práticos, erros comuns e exercícios resolvidos

Então se prepare e vamos nessa!

Vá Direto ao Assunto…

Introdução

As classes podem ser definidas como modelos para a criação de objetos.

Elas contêm atributos (variáveis) e métodos (funções) que definem o comportamento do objeto criado a partir da classe.

Ao criar uma classe, estamos criando um tipo de dado personalizado e reutilizável em nosso código.

A utilização de classes é extremamente importante na programação orientada a objetos, pois permite a abstração de problemas complexos em entidades menores, além de facilitar a manutenção e reutilização do código. Se você ainda não conhece os conceitos gerais do paradigma, comece pela nossa introdução à Programação Orientada a Objetos no Python.

Pense assim: a classe Carro é a planta do projeto (diz que todo carro tem marca, modelo e sabe acelerar); cada carro que sai da fábrica é um objeto diferente, com seus próprios valores. A documentação oficial explica o modelo de classes do Python em detalhes no tutorial de Classes.

Definindo uma Classe

No Python, podemos definir uma classe utilizando a palavra-chave class, seguida pelo nome da classe.

O nome da classe deve seguir algumas convenções, como começar com uma letra maiúscula e utilizar a notação CamelCase (iniciais das palavras compostas são maiúsculas e não há espaços ou underscores).

Aqui está um exemplo simples de uma classe chamada Pessoa:

1
2
class Pessoa:
    pass

Neste exemplo, utilizamos a palavra-chave pass para indicar que a definição da classe está vazia.

Isso permite que possamos criar a classe sem implementar nenhum atributo ou método por enquanto.

Criando um Objeto

Uma vez definida a classe, podemos criar objetos a partir dela.

Esses objetos são chamados de instâncias da classe.

Para criar uma instância, utilizamos o nome da classe seguido de parênteses:

1
pessoa1 = Pessoa()

No exemplo acima, criamos uma instância da classe Pessoa e a atribuímos à variável pessoa1.

Agora, podemos acessar essa instância e manipulá-la.

Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine as PyDicas e receba 30 dias do melhor conteúdo Python na sua Caixa de Entrada: direto e sem enrolação!

Atributos da Classe

As classes podem ter atributos, que são variáveis que pertencem à classe e são compartilhadas por todas as instâncias criadas a partir dessa classe.

Os atributos representam as características que o objeto da classe possui.

Podemos adicionar um atributo à classe Pessoa da seguinte forma:

1
2
3
class Pessoa:
    nome = "João"
    idade = 30

No exemplo acima, adicionamos os atributos nome e idade à classe Pessoa.

Agora, todas as instâncias dessa classe terão esses atributos definidos.

Podemos acessar e modificar os atributos de uma instância da seguinte forma:

1
2
3
4
5
pessoa1 = Pessoa()
print(pessoa1.nome)  # Saída: João

pessoa1.nome = "Maria"
print(pessoa1.nome)  # Saída: Maria

No exemplo acima, acessamos o atributo nome da instância pessoa1 e o modificamos para “Maria”.

Podemos fazer o mesmo com o atributo idade.

Métodos da Classe

Além de atributos, as classes também podem ter métodos, que são funções que pertencem à classe e podem ser chamadas pelas instâncias dessa classe. Tudo o que você já sabe sobre funções em Python (parâmetros, valores padrão, return) vale para métodos; a diferença é o primeiro parâmetro, self.

Os métodos representam os comportamentos que o objeto da classe pode realizar.

Podemos adicionar um método à classe Pessoa da seguinte forma:

1
2
3
class Pessoa:
    def falar(self, mensagem):
        print(f"{self.nome} diz: {mensagem}")

No exemplo acima, adicionamos o método falar à classe Pessoa.

O método recebe dois parâmetros: self e mensagem.

O parâmetro self é uma referência à própria instância da classe, permitindo o acesso aos atributos e métodos dessa instância.

Podemos chamar o método falar da seguinte forma:

1
2
3
pessoa1 = Pessoa()
pessoa1.nome = "João"
pessoa1.falar("Olá!")  # Saída: João diz: Olá!

E a saída será:

1
João diz: Olá!

No exemplo acima, chamamos o método falar da instância pessoa1, passando a mensagem “Olá!” como parâmetro.

:bulb: Criei o Ebookr.ai, uma plataforma que usa IA para gerar ebooks profissionais sobre qualquer tema - com capa gerada por IA, infográficos automáticos e exportação em PDF. Confere!

Construtor da Classe

O construtor é um método especial que é executado automaticamente quando uma instância da classe é criada.

No Python, o construtor é chamado de __init__.

Podemos utilizar o construtor para definir valores iniciais para os atributos da classe.

Aqui está um exemplo de como definir um construtor na classe Pessoa:

1
2
3
4
class Pessoa:
    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

No exemplo acima, definimos o construtor __init__ com os parâmetros nome e idade.

Dentro do construtor, atribuímos os valores desses parâmetros aos atributos da classe Pessoa.

Podemos criar uma instância da classe Pessoa e passar os valores para o construtor da seguinte forma:

1
2
3
pessoa1 = Pessoa("João", 30)
print(pessoa1.nome)
print(pessoa1.idade)

Resultando em:

1
2
João
30

No exemplo acima, criamos uma instância da classe Pessoa com o nome “João” e idade 30.

Ao imprimir os valores dos atributos nome e idade, obtemos os valores passados no construtor.

Dois detalhes que costumam cair em prova e entrevista:

  • Tecnicamente, __init__ é o inicializador: quem cria o objeto na memória é o método __new__, e o __init__ recebe esse objeto já criado (em self) para preencher os atributos. Por isso o __init__ não tem return (ele deve retornar None).
  • Não confunda o método __init__ com o arquivo __init__.py, que marca uma pasta como pacote Python. Explicamos esse arquivo em pra que serve o __init__.py no Python.

Herança de Classes

Uma vantagem das classes é a possibilidade de criar novas classes a partir de classes existentes. Isso é chamado de Herança.

A classe derivada herda todos os atributos e métodos da classe base.

Aqui está um exemplo de como criar uma classe derivada (também chamada de subclasse) a partir da classe Pessoa. Para o exemplo ficar completo, a Pessoa agora reúne o construtor e o método falar que vimos acima:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Pessoa:
    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

    def falar(self, mensagem):
        print(f"{self.nome} diz: {mensagem}")


class Estudante(Pessoa):
    def __init__(self, nome, idade, matricula):
        super().__init__(nome, idade)
        self.matricula = matricula

No exemplo acima, criamos a classe Estudante que herda da classe Pessoa.

Utilizamos o método super().__init__() para chamar o construtor da classe Pessoa e passar os valores para os atributos nome e idade.

Podemos criar uma instância da classe Estudante e acessar os atributos e métodos da classe base da seguinte forma:

1
2
3
4
5
estudante1 = Estudante("Maria", 18, "12345")
print(estudante1.nome)
print(estudante1.idade)
print(estudante1.matricula)
estudante1.falar("Olá!")

O que resultará em:

1
2
3
4
Maria
18
12345
Maria diz: Olá!

No exemplo acima, criamos uma instância da classe Estudante com o nome “Maria”, idade 18 e matrícula “12345”.

Ao imprimir os valores dos atributos e ao chamar o método falar, temos acesso aos atributos e métodos da classe base Pessoa.

O que é self em Python

self é o primeiro parâmetro de todo método de instância e representa o objeto que chamou o método. É por meio dele que o método sabe de qual objeto deve ler ou alterar os atributos.

Você não passa o self na chamada: o Python faz isso sozinho. Quando você escreve ana.saudar(), o Python executa Pessoa.saudar(ana):

1
2
3
4
5
6
7
8
9
10
11
12
class Pessoa:
    def __init__(self, nome):
        self.nome = nome

    def saudar(self):
        return f"Olá, eu sou {self.nome}"

ana = Pessoa("Ana")
bruno = Pessoa("Bruno")

print(ana.saudar())          # Olá, eu sou Ana
print(Pessoa.saudar(bruno))  # Olá, eu sou Bruno

O método saudar é um só, definido na classe, mas cada chamada recebe um self diferente. Por isso ana.saudar() usa o nome “Ana” e bruno.saudar() usa o nome “Bruno”.

Três regras práticas sobre o self:

  • Ele precisa estar na definição de todo método de instância (def saudar(self):). Se você esquecer, o Python gera um TypeError (veja em Erros comuns).
  • Todo atributo do objeto é acessado com self.: dentro do método, nome sozinho é uma variável local; self.nome é o atributo do objeto.
  • self é convenção, não palavra reservada. Funcionaria com outro nome, mas todo código Python usa self, e você também deve usar.

Métodos de classe (@classmethod) recebem cls no lugar de self, e métodos estáticos (@staticmethod) não recebem nenhum dos dois. Veja a comparação na seção sobre métodos de instância, de classe e estáticos, mais abaixo.

Conclusão

As classes são fundamentais na linguagem de programação Python e permitem a criação de código modular, organizado e reutilizável.

Elas fornecem uma forma concisa e eficiente de representar e manipular objetos em nossos programas.

Métodos Especiais (Magic Methods)

str vs repr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Produto:
    def __init__(self, nome, preco):
        self.nome = nome
        self.preco = preco

    def __str__(self):
        # Para usuários finais (legível)
        return f"{self.nome} - R$ {self.preco:.2f}"

    def __repr__(self):
        # Para desenvolvedores (debug)
        return f"Produto(nome='{self.nome}', preco={self.preco})"

p = Produto("Mouse", 45.90)
print(str(p))   # Mouse - R$ 45.90
print(repr(p))  # Produto(nome='Mouse', preco=45.9)

len e getitem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Playlist:
    def __init__(self, nome):
        self.nome = nome
        self.musicas = []

    def adicionar(self, musica):
        self.musicas.append(musica)

    def __len__(self):
        return len(self.musicas)

    def __getitem__(self, index):
        return self.musicas[index]

playlist = Playlist("Favoritas")
playlist.adicionar("Música 1")
playlist.adicionar("Música 2")

print(len(playlist))  # 2
print(playlist[0])    # Música 1

Métodos de Instância vs Classe vs Estáticos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Contador:
    # Atributo de classe (compartilhado)
    total_instancias = 0

    def __init__(self, nome):
        # Atributo de instância (único por objeto)
        self.nome = nome
        self.contagem = 0
        Contador.total_instancias += 1

    # Método de instância (acessa self)
    def incrementar(self):
        self.contagem += 1

    # Método de classe (acessa cls)
    @classmethod
    def total(cls):
        return cls.total_instancias

    # Método estático (não acessa nada)
    @staticmethod
    def validar_nome(nome):
        return len(nome) > 0

c1 = Contador("A")
c2 = Contador("B")

c1.incrementar()
print(c1.contagem)  # 1
print(c2.contagem)  # 0
print(Contador.total())  # 2
print(Contador.validar_nome("teste"))  # True

Casos de Uso Reais

1. Sistema de Usuários

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from datetime import datetime

class Usuario:
    def __init__(self, username, email):
        self.username = username
        self.email = email
        self.criado_em = datetime.now()
        self.ativo = True

    def desativar(self):
        self.ativo = False

    def dias_desde_criacao(self):
        return (datetime.now() - self.criado_em).days

    def __str__(self):
        status = "Ativo" if self.ativo else "Inativo"
        return f"{self.username} ({status})"

user = Usuario("alice", "[email protected]")
print(user)  # alice (Ativo)
print(f"Dias: {user.dias_desde_criacao()}")

2. Catálogo de Produtos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Produto:
    desconto_global = 0.1  # 10% desconto

    def __init__(self, nome, preco, estoque):
        self.nome = nome
        self.preco = preco
        self.estoque = estoque

    def preco_com_desconto(self):
        return self.preco * (1 - Produto.desconto_global)

    def vender(self, quantidade):
        if quantidade <= self.estoque:
            self.estoque -= quantidade
            return True
        return False

    @classmethod
    def alterar_desconto(cls, novo_desconto):
        cls.desconto_global = novo_desconto

p1 = Produto("Teclado", 200, 10)
p2 = Produto("Mouse", 100, 20)

print(p1.preco_com_desconto())  # 180.0

Produto.alterar_desconto(0.2)  # 20% agora
print(p1.preco_com_desconto())  # 160.0
print(p2.preco_com_desconto())  # 80.0

Atributos de Classe vs Instância

  • Atributo de classe é definido no corpo da classe, fora dos métodos. Existe uma única cópia, compartilhada por todos os objetos.
  • Atributo de instância é criado com self.nome = ..., normalmente no __init__. Cada objeto tem o seu.

Quando você lê objeto.atributo, o Python procura primeiro no objeto e, se não encontrar, procura na classe. Já uma atribuição como objeto.atributo = valor sempre cria (ou altera) o atributo no objeto, sem mexer na classe. O exemplo abaixo mostra as duas coisas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Carro:
    # Atributo de classe (compartilhado por todos)
    rodas = 4

    def __init__(self, marca, modelo):
        # Atributos de instância (únicos por objeto)
        self.marca = marca
        self.modelo = modelo

c1 = Carro("Toyota", "Corolla")
c2 = Carro("Honda", "Civic")

print(c1.rodas)  # 4 (acessa classe)
print(c2.rodas)  # 4 (acessa classe)

# Modificar instância (apenas c1)
c1.rodas = 6  # Cria atributo de instância
print(c1.rodas)  # 6
print(c2.rodas)  # 4 (ainda usa classe)

# Modificar classe (afeta todos)
Carro.rodas = 8
print(c2.rodas)  # 8 (atualizado)
print(c1.rodas)  # 6 (instância sobrescreve)

Regra prática: use atributo de classe para constantes e valores realmente compartilhados (como rodas = 4 ou um contador de instâncias). Para qualquer dado que muda de objeto para objeto, e principalmente para listas e dicionários, use atributo de instância criado no __init__. Um list como atributo de classe é compartilhado por todos os objetos, um bug clássico que mostramos em Erros comuns.

Construir essa base de POO com clareza é o que separa quem só copia código de quem entende classes de verdade - e é exatamente isso que ensinamos, do básico ao avançado, na Jornada Python:

Dataclasses: classes com menos código

Muitas classes existem só para guardar dados, e você acaba escrevendo sempre o mesmo __init__ que copia parâmetros para self, mais um __repr__ e um __eq__. O decorador @dataclass, do módulo dataclasses (Python 3.7+), gera esses métodos a partir das anotações de tipo:

1
2
3
4
5
6
7
8
9
10
11
12
from dataclasses import dataclass

@dataclass
class Produto:
    nome: str
    preco: float
    estoque: int = 0  # valor padrão

teclado = Produto("Teclado", 199.9)
print(teclado)                                # Produto(nome='Teclado', preco=199.9, estoque=0)
print(teclado == Produto("Teclado", 199.9))  # True
print(teclado.estoque)                        # 0

Sem escrever nenhum método, você ganhou:

  • __init__ com os parâmetros nome, preco e estoque (este com valor padrão);
  • __repr__ legível, ótimo para debug;
  • __eq__ que compara os objetos pelo conteúdo (numa classe comum, == compara se é o mesmo objeto na memória e daria False).

Uma dataclass continua sendo uma classe normal: você pode adicionar métodos, usar herança e decorators como @property. Para listas e dicionários como valor padrão, use field(default_factory=list), que cria uma lista nova para cada objeto. Vamos mais fundo (frozen, field, comparação e casos práticos) no post dedicado a dataclasses no Python.

Classe, dataclass, dicionário ou namedtuple: quando usar cada um

Você precisa de Use Exemplo
Dados e comportamento (métodos, regras, validação) Classe comum class ContaBancaria: com depositar() e sacar()
Principalmente guardar dados com nomes e tipos, com pouco código @dataclass Produto(nome, preco, estoque)
Dados imutáveis e leves, que podem ser desempacotados como tupla namedtuple / typing.NamedTuple Ponto(x=1, y=2)
Chaves dinâmicas ou dados vindos de JSON, sem estrutura fixa dict {"nome": "Ana", "idade": 30}
Controlar leitura e escrita de um atributo (validação, valor calculado) Classe com @property preco que não aceita valor negativo

Os 4 pilares da POO em Python

A Programação Orientada a Objetos se apoia em quatro pilares. Em resumo, e com o jeito Python de aplicar cada um:

  • Encapsulamento: esconder os detalhes internos e expor uma interface simples. Python não tem private; a convenção é prefixar com _ o que é interno (self._saldo) e usar @property para controlar leitura e escrita.
  • Herança: uma classe filha reaproveita e estende a classe mãe, como Estudante(Pessoa) na seção Herança de Classes, usando super() para chamar o código da mãe.
  • Polimorfismo: objetos de classes diferentes respondem ao mesmo método, cada um do seu jeito. Quem chama não precisa saber a classe exata.
  • Abstração: modelar só o que importa. Em Python, classes abstratas do módulo abc definem métodos que as filhas são obrigadas a implementar.

O exemplo abaixo junta herança, polimorfismo e abstração:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from abc import ABC, abstractmethod

class Forma(ABC):
    @abstractmethod
    def area(self):
        ...

class Quadrado(Forma):
    def __init__(self, lado):
        self.lado = lado

    def area(self):
        return self.lado ** 2

class Circulo(Forma):
    def __init__(self, raio):
        self.raio = raio

    def area(self):
        return round(3.14159 * self.raio ** 2, 2)

for forma in [Quadrado(3), Circulo(2)]:
    print(type(forma).__name__, forma.area())

Saída:

1
2
Quadrado 9
Circulo 12.57

O for chama forma.area() sem saber se é quadrado ou círculo (polimorfismo). E como Forma é abstrata, Forma() gera TypeError: não dá para instanciar uma classe que tem método abstrato sem implementação.

Cada pilar, com mais exemplos, está explicado na nossa introdução à Programação Orientada a Objetos. Para ver POO aplicada a um problema de arquitetura, confira o padrão de projeto Abstract Factory em Python.

Erros comuns

1. Esquecer o self na definição do método

1
2
3
4
5
6
class Pessoa:
    def saudar():
        return "Olá!"

p = Pessoa()
p.saudar()
1
TypeError: Pessoa.saudar() takes 0 positional arguments but 1 was given

Você não passou nenhum argumento, mas o Python sempre envia o próprio objeto como primeiro argumento. Como saudar() não tem parâmetro para recebê-lo, dá erro. Correção: def saudar(self):.

2. Chamar o método pela classe, sem instância

1
2
3
4
5
class Pessoa:
    def saudar(self):
        return "Olá!"

Pessoa.saudar()
1
TypeError: Pessoa.saudar() missing 1 required positional argument: 'self'

Chamado pela classe, o método não tem objeto para colocar em self. Crie um objeto e chame por ele: Pessoa().saudar(). Se o método realmente não depende de um objeto, transforme-o em @staticmethod ou @classmethod.

3. Atributo de classe mutável compartilhado entre instâncias

1
2
3
4
5
6
7
8
9
10
11
12
13
class Aluno:
    notas = []  # atributo de classe: UMA lista para todos

    def __init__(self, nome):
        self.nome = nome

    def adicionar_nota(self, nota):
        self.notas.append(nota)

ana = Aluno("Ana")
bruno = Aluno("Bruno")
ana.adicionar_nota(10)
print(bruno.notas)  # [10]  -> a nota da Ana apareceu no Bruno!

Não há traceback, e é isso que torna esse bug perigoso. self.notas.append(...) não cria atributo no objeto: ele encontra a lista da classe e a modifica, e todos os alunos enxergam a mesma lista. Correção: crie a lista no __init__.

1
2
3
4
5
6
7
8
9
10
11
12
class Aluno:
    def __init__(self, nome):
        self.nome = nome
        self.notas = []  # uma lista nova para cada objeto

    def adicionar_nota(self, nota):
        self.notas.append(nota)

ana = Aluno("Ana")
bruno = Aluno("Bruno")
ana.adicionar_nota(10)
print(ana.notas, bruno.notas)  # [10] []

4. AttributeError por erro de digitação

1
2
3
4
5
6
class Pessoa:
    def __init__(self, nome):
        self.nome = nome

p = Pessoa("Ana")
print(p.nmoe)
1
AttributeError: 'Pessoa' object has no attribute 'nmoe'

O objeto só tem os atributos que foram criados nele (ou na classe). Confira o nome no __init__; versões recentes do Python ainda sugerem Did you mean: 'nome'? no final da mensagem. O mesmo erro aparece se você usar um atributo que só é criado em outro método que ainda não foi chamado.

5. Esquecer de chamar a classe (Pessoa em vez de Pessoa())

1
2
3
4
5
6
class Pessoa:
    def __init__(self, nome):
        self.nome = nome

p = Pessoa  # faltou chamar a classe
print(p.nome)
1
AttributeError: type object 'Pessoa' has no attribute 'nome'

Sem os parênteses, p recebe a própria classe, não um objeto, e o __init__ nunca roda. A mensagem “type object” é a pista: você está mexendo na classe. Correção: p = Pessoa("Ana"). Se, nesse mesmo caso, você chamar um método (p.saudar()), o erro vira TypeError: ... missing 1 required positional argument: 'self'.

Exercícios resolvidos

Tente resolver cada exercício antes de abrir a solução. Todos os códigos foram executados e as saídas conferidas. Quer praticar POO com projetos guiados, do básico ao avançado? Conheça o nosso curso de Python completo, a Jornada Python.

Exercício 1. Crie uma classe Retangulo que recebe largura e altura no construtor e tem um método area(). Mostre a área de um retângulo 3 x 4.

Ver solução
1
2
3
4
5
6
7
8
9
10
class Retangulo:
    def __init__(self, largura, altura):
        self.largura = largura
        self.altura = altura

    def area(self):
        return self.largura * self.altura

r = Retangulo(3, 4)
print(r.area())

Saída: 12

O __init__ guarda os valores em self, e o método area() usa esses atributos do próprio objeto.

Exercício 2. (Questão de prova) Sobre classes e objetos em Python, assinale a alternativa correta:

a) Uma classe é uma instância de um objeto.
b) Um objeto é uma instância de uma classe.
c) O argumento self precisa ser passado manualmente em toda chamada de método.
d) O método __init__ deve retornar o objeto criado.

Ver solução
1
2
3
4
5
6
class Pessoa:
    pass

p = Pessoa()
print(isinstance(p, Pessoa))
print(type(p).__name__)

Saída: True e Pessoa

Resposta: b. A classe é o molde e o objeto é a instância, por isso a alternativa a está invertida. A c está errada porque o Python passa o self automaticamente, e a d porque o __init__ só inicializa o objeto e retorna None.

Exercício 3. Crie uma classe ContaBancaria com titular e saldo (padrão 0) e os métodos depositar(valor) e sacar(valor). O saque deve retornar False e não alterar o saldo se não houver dinheiro suficiente.

Ver solução
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ContaBancaria:
    def __init__(self, titular, saldo=0):
        self.titular = titular
        self.saldo = saldo

    def depositar(self, valor):
        self.saldo += valor

    def sacar(self, valor):
        if valor > self.saldo:
            return False
        self.saldo -= valor
        return True

conta = ContaBancaria("Ana", 100)
conta.depositar(50)
print(conta.sacar(500))
print(conta.sacar(30))
print(conta.saldo)

Saída: False, True e 120

O saldo foi para 150 com o depósito, o saque de 500 foi recusado e o de 30 deixou 120. A regra de negócio fica dentro da classe, e não espalhada pelo código.

Exercício 4. (Questão de prova) Qual é a saída do código abaixo?

1
2
3
4
5
6
7
8
9
10
class Contador:
    total = 0

    def __init__(self):
        Contador.total += 1

a = Contador()
b = Contador()
c = Contador()
print(Contador.total, a.total)

a) 0 0
b) 1 1
c) 3 3
d) 3 1

Ver solução

Saída: 3 3

Resposta: c. total é atributo de classe e o __init__ incrementa Contador.total (a classe, não o objeto) a cada objeto criado. Como a não tem atributo total próprio, a.total busca na classe e também mostra 3.

Exercício 5. Crie uma classe Livro com titulo e autor de forma que print(livro) mostre 'Dom Casmurro', de Machado de Assis.

Ver solução
1
2
3
4
5
6
7
8
9
10
class Livro:
    def __init__(self, titulo, autor):
        self.titulo = titulo
        self.autor = autor

    def __str__(self):
        return f"'{self.titulo}', de {self.autor}"

livro = Livro("Dom Casmurro", "Machado de Assis")
print(livro)

Saída: 'Dom Casmurro', de Machado de Assis

O print() chama str() no objeto, que por sua vez usa o método __str__. Sem ele, você veria algo como <__main__.Livro object at 0x...>.

Exercício 6. Crie uma classe Animal com nome e um método falar() que retorna "...". Depois crie Cachorro e Gato, que herdam de Animal e sobrescrevem falar(). Percorra uma lista com um de cada e mostre o que cada um fala.

Ver solução
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal:
    def __init__(self, nome):
        self.nome = nome

    def falar(self):
        return "..."

class Cachorro(Animal):
    def falar(self):
        return "Au au!"

class Gato(Animal):
    def falar(self):
        return "Miau!"

for bicho in [Cachorro("Rex"), Gato("Mimi"), Animal("Genérico")]:
    print(f"{bicho.nome}: {bicho.falar()}")

Saída:

1
2
3
Rex: Au au!
Mimi: Miau!
Genérico: ...

Cachorro e Gato herdam o __init__ de Animal (herança) e cada um responde a falar() do seu jeito (polimorfismo).

Exercício 7. (Questão de prova) Qual é a saída do código abaixo?

1
2
3
4
5
6
7
8
9
10
11
12
13
from dataclasses import dataclass

class PontoComum:
    def __init__(self, x, y):
        self.x = x
        self.y = y

@dataclass
class PontoData:
    x: int
    y: int

print(PontoComum(1, 2) == PontoComum(1, 2), PontoData(1, 2) == PontoData(1, 2))

a) True True
b) False True
c) False False
d) True False

Ver solução

Saída: False True

Resposta: b. Numa classe comum, sem __eq__, o == verifica se é o mesmo objeto na memória, e são dois objetos diferentes. A dataclass gera um __eq__ que compara os campos, e x e y são iguais.

Exercício 8. Crie uma classe Temperatura que guarda celsius e tenha um “construtor alternativo” de_fahrenheit(f), usando @classmethod, para criar o objeto a partir de uma temperatura em Fahrenheit. Teste com 212 °F.

Ver solução
1
2
3
4
5
6
7
8
9
10
11
class Temperatura:
    def __init__(self, celsius):
        self.celsius = celsius

    @classmethod
    def de_fahrenheit(cls, fahrenheit):
        return cls((fahrenheit - 32) * 5 / 9)

t = Temperatura.de_fahrenheit(212)
print(t.celsius)
print(isinstance(t, Temperatura))

Saída: 100.0 e True

O @classmethod recebe a classe em cls e chama cls(...) para criar o objeto. Esse padrão é o mesmo de datetime.fromtimestamp() e dict.fromkeys() na biblioteca padrão.

Conclusão

Neste guia de Classes e Objetos, você aprendeu:

✅ Declaração - Criar classes e instanciar objetos
✅ Métodos especiais - init, str, repr, len
✅ Tipos de métodos - Instância, classe (@classmethod), estáticos (@staticmethod)
✅ Casos práticos - Usuários, produtos, contadores
✅ Atributos - Classe (compartilhado) vs Instância (único)

Principais lições:

  • self refere-se à instância atual
  • __init__ é o construtor (inicializa objeto)
  • __str__ para exibição, __repr__ para debug
  • @classmethod acessa atributos de classe
  • @staticmethod não acessa nem self nem cls

Próximos passos:

  • Aprenda @property para getters/setters
  • Explore Dataclasses (menos boilerplate)
  • Estude herança e polimorfismo
  • Pratique Design Patterns

Neste artigo, vimos como definir uma classe, criar objetos, adicionar atributos e métodos, utilizar um construtor e explorar a herança de classes.

Espero que este artigo tenha sido útil e que você possa aproveitar ao máximo as classes na sua jornada de programação Python!

Nos vemos no próximo Post! :wave:

Perguntas frequentes

O que é uma classe em Python?

Uma classe é um molde que define os atributos (dados) e os métodos (comportamentos) que os objetos criados a partir dela terão. Em Python ela é criada com a palavra-chave class, por exemplo class Pessoa:, e cada chamada Pessoa() cria um novo objeto desse tipo.

Qual a diferença entre classe e objeto?

A classe é a definição (o molde) e o objeto é uma instância concreta criada a partir dela. Em ana = Pessoa('Ana'), Pessoa é a classe e ana é o objeto. Uma mesma classe pode gerar vários objetos, cada um com seus próprios valores de atributos.

Para que serve o init em Python?

O __init__ é o método que o Python executa automaticamente logo depois de criar um objeto, e serve para inicializar os atributos da instância. Ele é chamado de construtor no dia a dia: def __init__(self, nome): self.nome = nome. Os argumentos passados em Pessoa('Ana') chegam nos parâmetros do __init__. Não confunda com o arquivo __init__.py, que marca uma pasta como pacote.

O que é self em Python?

self é o primeiro parâmetro dos métodos de instância e representa o próprio objeto que chamou o método. O Python passa esse argumento automaticamente: ana.saudar() equivale a Pessoa.saudar(ana). É por meio de self.atributo que o método lê e altera os dados daquele objeto. O nome self é uma convenção, não uma palavra reservada.

Qual a diferença entre atributo de classe e atributo de instância?

O atributo de classe é definido no corpo da classe, fora dos métodos, e é compartilhado por todos os objetos (ex.: rodas = 4). O atributo de instância é criado com self.nome = ..., normalmente no __init__, e pertence a cada objeto. Cuidado com listas e dicionários como atributo de classe: todos os objetos passam a alterar a mesma lista.

O que é dataclass em Python?

É um decorador do módulo dataclasses (Python 3.7+) que gera automaticamente __init__, __repr__ e __eq__ a partir das anotações de tipo da classe. Com @dataclass e as linhas nome: str e preco: float, você já pode fazer Produto('Mouse', 50.0), imprimir o objeto de forma legível e comparar dois objetos pelo conteúdo.

Quais são os 4 pilares da programação orientada a objetos?

Encapsulamento (esconder detalhes internos e expor uma interface, em Python com _atributo e @property), herança (uma classe filha reaproveita a classe mãe, class Estudante(Pessoa)), polimorfismo (objetos diferentes respondem ao mesmo método cada um do seu jeito) e abstração (modelar só o essencial, em Python com classes abstratas do módulo abc).

Em Python, qual palavra-chave é usada para definir uma classe?

A palavra-chave é class, seguida do nome da classe em CamelCase e de dois-pontos: class ContaBancaria:. Alternativas comuns em provas estão erradas: def define funções, object é a classe base de todas as classes e new não existe em Python (o objeto é criado chamando a classe, como ContaBancaria()).

Começe agora sua Jornada na Programação!

Não deixe para amanhã o sucesso que você pode começar a construir hoje!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.