✅ 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. -
@dataclassgera__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 é
selfe 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
- O que é self em Python
- Conclusão
- Métodos Especiais (Magic Methods)
- Métodos de Instância vs Classe vs Estáticos
- Casos de Uso Reais
- Atributos de Classe vs Instância
- Dataclasses: classes com menos código
- Os 4 pilares da POO em Python
- Erros comuns
- Exercícios resolvidos
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? ![]()
Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?
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.
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 (emself) para preencher os atributos. Por isso o__init__não temreturn(ele deve retornarNone). - 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__.pyno 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 umTypeError(veja em Erros comuns). -
Todo atributo do objeto é acessado com
self.: dentro do método,nomesozinho é 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 usaself, 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âmetrosnome,precoeestoque(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 dariaFalse).
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@propertypara 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, usandosuper()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
abcdefinem 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! ![]()
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()).
"Porque o Senhor dá a sabedoria, e da sua boca vem a inteligência e o entendimento" Pv 2:6