Seus objetos vão armazenar nomes, descrições, CPFs, endereços — tudo como strings. Dominar os métodos de string é essencial para manipular esses atributos e para construir um bom __str__.
| Método | O que faz | Exemplo |
|---|---|---|
.upper() | Tudo em maiúsculas | "ana".upper() → "ANA" |
.lower() | Tudo em minúsculas | "ANA".lower() → "ana" |
.strip() | Remove espaços nas bordas | " ana ".strip() → "ana" |
.split(sep) | Divide em lista | "a,b,c".split(",") → ["a","b","c"] |
.replace(a, b) | Substitui ocorrências | "oi mundo".replace("oi","olá") |
.startswith(s) | Começa com? | "Ana".startswith("A") → True |
.endswith(s) | Termina com? | "foto.jpg".endswith(".jpg") |
.capitalize() | Primeira letra maiúscula | "ana silva".capitalize() |
.title() | Cada palavra capitalizada | "ana silva".title() → "Ana Silva" |
nome = "Ana Silva"
print(len(nome)) # 9 — quantidade de caracteres
print("Silva" in nome) # True — verifica se está contida Métodos de string não modificam a string original — eles retornam uma nova string. Você precisa guardar o resultado.
nome = "ana"
nome.upper() # resultado vai pro lixo
print(nome) # ainda "ana"
nome = nome.upper() # agora sim — guarda o novo valor
print(nome) # "ANA" class Pessoa:
# Salvando o retorno na variável
def __init__(self, nome):
self.nome = nome.strip().title() # limpa e capitaliza na entrada
def __str__(self):
return f"Pessoa: {self.nome.upper()}" # maiúsculas na saída Nas classes que criamos, os atributos frequentemente são listas — histórico de operações, notas de alunos, itens de carrinho. Dominar os métodos de lista é essencial para trabalhar com esses atributos.
| Método / Operação | O que faz | Exemplo |
|---|---|---|
append(item) | Adiciona ao final | lista.append("João") |
pop() | Remove e retorna o último | ultimo = lista.pop() |
pop(i) | Remove e retorna o índice i | primeiro = lista.pop(0) |
remove(item) | Remove a 1ª ocorrência pelo valor | lista.remove("João") |
insert(i, item) | Insere na posição i | lista.insert(0, "início") |
len(lista) | Quantidade de itens | len(lista) |
item in lista | Verifica se existe | "João" in lista |
sort() | Ordena no lugar | lista.sort() |
sorted(lista) | Retorna nova lista ordenada | nova = sorted(lista) |
clear() | Remove todos os itens | lista.clear() |
nomes = ["Ana", "Bruno", "Carlos"]
nomes.pop() # remove e retorna "Carlos" (último)
nomes.pop(0) # remove e retorna "Ana" (índice 0)
nomes.remove("Bruno") # remove pelo valor — sem retorno notas = [8.0, 7.5, 9.0]
print(notas[-1]) # 9.0 — último item
print(notas[-2]) # 7.5 — penúltimo class ContaBancaria:
def __init__(self, titular):
self.titular = titular
self.historico = [] # lista vazia como atributo
def depositar(self, valor):
self.saldo += valor
self.historico.append(f"+ R$ {valor:.2f}") # append aqui
def ultima_operacao(self):
if len(self.historico) == 0:
return "Nenhuma operação"
return self.historico[-1] # índice -1 = último Antes de falar de métodos, precisamos entender que existem dois lugares onde o Python pode guardar um dado dentro de uma classe.
São criados dentro do __init__ usando self. Cada objeto tem sua própria cópia.
São definidos diretamente na classe, fora de qualquer método. Todos os objetos daquela classe enxergam o mesmo valor.
class Conta:
taxa = 0.05 # Atributo de CLASSE (Global)
def __init__(self, titular):
self.titular = titular # Atributo de INSTÂNCIA (Individual) | Tipo | Onde mora | Uso comum |
|---|---|---|
| Instância | No objeto (self) | Nomes, saldos, IDs, características únicas. |
| Classe | Na Classe (cls) | Configurações globais, contadores de objetos, constantes. |
Tudo que você fez nas aulas 01 e 02 — funções dentro de uma classe que recebem self — tem um nome: método de instância.
Um método de instância:
self como primeiro parâmetroselfclass ContaBancaria:
def __init__(self, titular, saldo):
self.titular = titular # atributo de instância
self.saldo = saldo # atributo de instância
def depositar(self, valor): # método de instância
self.saldo += valor # acessa o atributo via self
return self.saldo # return, não print | print dentro do método | return dentro do método |
|---|---|
| Exibe na tela — o valor desaparece | Devolve o valor para quem chamou |
| Não pode ser reutilizado | Pode ser guardado, usado em cálculos |
| Use para feedback ao usuário | Use para lógica e composição |
Dentro da classe, qualquer método pode chamar outro via self.metodo(). Isso evita repetição de código.
def situacao(self):
media = self.calcular_media() # delega para outro método
return "Aprovado" if media >= 7 else "Reprovado" Métodos auxiliares/internos são nomeados com _ no início. Tecnicamente funcionam igual, mas sinalizam "isso é detalhe de implementação".
def _registrar(self, operacao): # auxiliar interno
self.historico.append(operacao) Um método de classe não depende de um objeto específico — ele pertence à classe como um todo. É decorado com @classmethod e recebe cls (a classe) em vez de self (o objeto).
| Método de instância | Método de classe | |
|---|---|---|
| Primeiro parâmetro | self (o objeto) | cls (a classe) |
| Chamado em | Um objeto: conta.depositar() | A classe: ContaBancaria.criar_zerada() |
| Acessa | Dados daquele objeto | A classe toda / cria objetos |
| Quando usar | Comportamento do objeto | Construtores alternativos, configurações globais |
class ContaBancaria:
taxa_juros = 0.05 # atributo de CLASSE
@classmethod
def criar_zerada(cls, titular):
return cls(titular, 0)
@classmethod
def alterar_taxa(cls, nova_taxa):
cls.taxa_juros = nova_taxa Use @classmethod quando a operação faz sentido sem ter um objeto ainda criado. Os casos mais comuns são construtores alternativos e configurações globais.
Sem definir como um objeto deve ser exibido, o Python mostra apenas o endereço de memória, o que dificulta o processo de depuração:
p = Produto("Teclado", 149.90)
print(p) # Saída: <__main__.Produto object at 0x7f3c...> O método __str__ define a representação amigável e legível do objeto. É o método chamado automaticamente pelo print(), por f-strings ou pela função str().
def __str__(self):
return f"Produto: {self.nome} — R$ {self.preco:.2f}" O método __repr__ define a representação técnica. Ele deve mostrar exatamente como recriar o objeto no código.
def __repr__(self):
return f"Produto('{self.nome}', {self.preco})" | Característica | __str__ | __repr__ |
|---|---|---|
| Público | Usuário Final | Desenvolvedor / Debug |
| Objetivo | Legibilidade | Precisão Técnica |
| Chamado por | print(), str() | repr(), Listas, Console |
__repr__, o Python o utilizará como padrão para o print().Dunder vem de double underscore — dois underscores de cada lado. São também chamados de métodos mágicos. O Python os chama automaticamente em situações específicas — você nunca os chama diretamente pelo nome.
Quando você escreve len(lista), o Python internamente chama lista.__len__(). Quando escreve a + b, chama a.__add__(b). Os dunders são o que torna os operadores e funções built-in funcionarem com seus objetos.
| Dunder | Quando é chamado | Exemplo de uso |
|---|---|---|
__init__ | Ao criar um objeto | Cachorro("Rex") |
__str__ | print(obj) e f-strings | print(conta) |
__repr__ | Console / repr(obj) | repr(conta) |
__len__ | len(obj) | len(carrinho) |
__eq__ | obj1 == obj2 | conta1 == conta2 |
__lt__ | obj1 < obj2 | aluno1 < aluno2 |
__add__ | obj1 + obj2 | vetor1 + vetor2 |
__contains__ | item in obj | "João" in turma |
class Carrinho:
def __init__(self):
self.itens = []
def adicionar(self, item):
self.itens.append(item)
def __len__(self):
return len(self.itens) # permite: len(carrinho) O objetivo é entender o padrão: Python usa os dunders nos bastidores, e você pode defini-los para controlar o comportamento dos seus objetos. Ao longo do curso, você vai encontrando e usando cada um no contexto certo.
self.nome.strip() # resultado vai pro lixo self.nome = self.nome.strip() # guarda o resultado def __str__(self): return self.saldo # float → TypeError def __str__(self): return f"Saldo: R$ {self.saldo:.2f}" def area(self): print(3.14 * r**2) # valor desaparece def area(self): return 3.14 * r**2 media = calcular_media() # NameError media = self.calcular_media() def _str_(self): # não é dunder def __str__(self): # dois underscores Métodos de string nunca modificam a string original — sempre retornam uma nova. O correto é self.nome = nome.strip().
pop() remove por posição e retorna o item. remove(valor) remove por valor e não retorna nada.
__str__ é integrado ao Python: automático em prints e f-strings. exibir() é manual.
Use quando a ação faz sentido sem um objeto pronto, como criar um objeto de forma alternativa.
Sim! É comum usar self.calcular_media() dentro dele para compor a string de retorno.
Sim. Excelente para transformar uma entrada única de usuário em uma lista de dados.
Programação Orientada a Objetos com Python
Tecnologia em Análise e Desenvolvimento de Sistemas
destino da aula
No final desta aula você vai entender cada linha dessa classe — e saber escrever uma igual do zero.
class ContaBancaria:
taxa_juros = 0.05 # atributo de classe ← hoje
def __init__(self, titular, saldo=0):
self.titular = titular.strip().title() # método de string ← hoje
self.saldo = saldo
self.historico = [] # método de lista ← hoje
def depositar(self, valor):
self.saldo += valor
self.historico.append(f"+ R$ {valor:.2f}")
def sacar(self, valor):
if valor > self.saldo:
return False
self.saldo -= valor
self.historico.append(f"- R$ {valor:.2f}")
return True
@classmethod # método de classe ← hoje
def criar_zerada(cls, titular):
return cls(titular, 0)
def __str__(self): # representação ← hoje
return f"Conta de {self.titular} | Saldo: R$ {self.saldo:.2f}" bloco 1 · ferramentas do Python
Seus objetos vão armazenar nomes, CPFs e descrições como strings. Dominar esses métodos é essencial para manipular atributos e construir um bom __str__.
.strip(): Remove espaços nas bordas.title(): Cada palavra capitalizada.upper() / .lower(): Maiúsculas / minúsculas.replace(a, b): Substitui ocorrências.split(sep): Divide em lista.startswith(s): Começa com?len(s) / x in s: Tamanho / contémclass Pessoa:
def __init__(self, nome):
self.nome = nome.strip().title()
# Strings são IMUTÁVEIS — salve o resultado!
nome = " ana silva "
nome.strip() # ← resultado vai pro lixo
nome = nome.strip() # ← guarda o novo valor bloco 1 · ferramentas do Python
Atributos como histórico de operações, notas de alunos ou itens de carrinho são listas. Esses métodos são usados dentro dos seus objetos o tempo todo.
append(item): Adiciona ao finalpop(): Remove e retorna o últimopop(i): Remove e retorna pelo índiceremove(item): Remove a 1ª ocorrência do valorinsert(i, item): Insere na posição ilen(lista): Quantidade de itensitem in lista: Verifica se existesort() / sorted(): Ordena / retorna nova listahistorico = []
historico.append("+ R$ 500") # adiciona ao final
historico.append("- R$ 200")
print(historico[-1]) # último: "- R$ 200"
print(len(historico)) # 2
# pop vs remove
historico.pop() # remove pelo índice (retorna)
historico.remove("+ R$ 500") # remove pelo valor bloco 1 · na prática
O que acabamos de ver não é teoria isolada — é exatamente o que acontece dentro de qualquer classe bem construída.
class ContaBancaria:
def __init__(self, titular, saldo=0):
self.titular = titular.strip().title() # .strip() e .title()
self.saldo = saldo
self.historico = [] # lista vazia como atributo
def depositar(self, valor):
self.saldo += valor
self.historico.append(f"+ R$ {valor:.2f}") # .append()
def ultima_operacao(self):
if len(self.historico) == 0:
return "Nenhuma operação ainda"
return self.historico[-1] # índice negativo
c = ContaBancaria(" ana silva ")
print(c.titular) # "Ana Silva" — .title() limpou
c.depositar(500)
print(c.ultima_operacao()) # "+ R$ 500.00" bloco 2 · onde moram os dados
Antes de criar ações, precisamos entender quem é o "dono" da informação que estamos guardando.
Criados com self dentro do __init__. Cada objeto tem o seu próprio valor.
Criados na classe. Todos os objetos daquela classe compartilham o mesmo dado.
# Para mudar para TODOS: Conta.taxa = 0.06bloco 2 · métodos
Todo método de instância recebe self e acessa os dados do próprio objeto.
class ContaBancaria:
def __init__(self, titular, saldo):
self.titular = titular
self.saldo = saldo
def depositar(self, valor): # método de instância
self.saldo += valor
return self.saldo # retorna o novo saldo
conta = ContaBancaria("João", 1000)
novo = conta.depositar(500)
print(novo) # 1500 self dá ao método acesso a todos os atributos do objeto. Sem ele, o método não saberia de qual conta está falando.bloco 2 · três padrões essenciais
Evite que o valor desapareça na tela. Com return, ele pode ser guardado em variáveis ou reusado em cálculos.
# ❌ Errado: valor desaparece
def area(self):
print(self.l * self.a)
# ✅ Certo: valor reusável
def area(self):
return self.l * self.a Dentro da classe, qualquer método pode chamar outro via self.metodo(). Isso evita repetição de código.
def situacao(self):
# delega para outro método
media = self.calcular_media()
if media >= 7:
return "Aprovado"
return "Reprovado" O _ no início sinaliza um método interno de implementação que não faz parte da interface pública.
def depositar(self, v):
self.saldo += v
# método auxiliar
self._registrar(f"+ {v}")
def _registrar(self, op):
self.historico.append(op) bloco 2 · uma necessidade nova
ContaBancaria com saldo zero sem passar 0 toda hora# Módulo de instância não funciona aqui
# precisaria de um objeto JÁ EXISTENTE:
conta.criar_zerada() # ← mas qual "conta"?
# O que faz sentido é chamar NA CLASSE:
ContaBancaria.criar_zerada("Maria")
# Para isso existe: @classmethod bloco 2 · o contraste
| item | detalhe |
|---|---|
| Decorador | — (nenhum) vs @classmethod |
| 1º parâmetro | self (o objeto) vs cls (a classe) |
| Chamado em | objeto.metodo() vs Classe.metodo() |
| Acessa | Dados daquele objeto vs A classe toda / cria objetos |
| Quando usar | Comportamento do objeto vs Construtores alternativos, config global |
bloco 3 · representação
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
p = Produto("Teclado", 149.90)
print(p)
# <__main__.Produto object at 0x7f3c...> bloco 3 · o padrão por baixo
Dunder = double underscore. São chamados automaticamente pelo Python em situações específicas — você nunca os chama diretamente.
__init__ → ao criar __str__ → print()
__repr__ → repr() __len__ → len(obj) __eq__ → obj1 == obj2 __lt__ → obj1 < obj2
__add__ → obj1 + obj2 __contains__ → in __iter__ → for loop
bloco 3 · representação
Chamado automaticamente pelo Python quando você usa print(objeto) ou str(objeto).
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def __str__(self):
return f"Produto: {self.nome} | Preço: R$ {self.preco:.2f}"
p = Produto("Teclado", 149.90)
print(p) # Produto: Teclado | Preço: R$ 149.90
print(f"Item: {p}") # também funciona em f-strings! __str__ deve sempre retornar uma string. Use f-strings — elas garantem isso e ficam muito legíveis.bloco 3 · para desenvolvedores
__str__ — para o usuário. Legível, amigável__repr__ — para o desenvolvedor. Mostra como recriar o objeto__str__class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def __str__(self):
return f"{self.nome} — R$ {self.preco:.2f}"
def __repr__(self):
return f"Produto('{self.nome}', {self.preco})"
p = Produto("Teclado", 149.90)
print(p) # Teclado — R$ 149.90
print(repr(p)) # Produto('Teclado', 149.9) bloco 4 · antes da prática
Lembre-se: self.nome = nome.strip().
Tentar retornar um número direto (ex: return self.saldo) gera erro de tipo.
Cálculos exigem return para serem reusados.
Dentro da classe, use sempre self.metodo().
São sempre dois underscores de cada lado: __str__, não _str_.
bloco 4 · antes da prática
Métodos de string retornam uma nova string. Use self.nome = nome.strip() para guardar o resultado.
pop() remove pela posição e retorna o item. remove(valor) remove por valor e não retorna nada.
O __str__ é automático no print(). O exibir() precisa ser chamado manualmente.
Use @classmethod para ações que não dependem de um objeto já criado, como construtores alternativos.
Sim! Pode usar self.calcular_media() dentro dele para compor a string de retorno.
Sim. É ideal para transformar uma string de entrada em uma lista de dados para preencher o objeto.
bloco 5 · prática
Vamos construir juntos uma ContaBancaria com operações reais e saída legível.
Crie ContaBancaria com titular, saldo=0 e historico (lista). Métodos depositar e sacar com validação.
Crie extrato() que percorre o historico com for e imprime o saldo final formatado.
Crie o __str__ e refatore o extrato(): use print(self) no final para exibir o saldo usando a regra do __str__.
exercício · partes 1 e 2
class ContaBancaria:
def __init__(self, titular, saldo=0):
self.titular = titular
self.saldo = saldo
self.historico = [] # lista vazia
def depositar(self, valor):
self.saldo += valor
self.historico.append(f"+ R$ {valor:.2f}")
def sacar(self, valor):
if valor > self.saldo:
print("Saldo insuficiente!")
return False
self.saldo -= valor
self.historico.append(f"- R$ {valor:.2f}")
return True
def extrato(self):
print(f"=== Extrato de {self.titular} ===")
for op in self.historico: # for na lista
print(f" {op}")
print(f"Saldo atual: R$ {self.saldo:.2f}") exercício · parte 3
class ContaBancaria:
# ... __init__, depositar, sacar ...
def extrato(self):
print(f"=== Extrato de {self.titular} ===")
for op in self.historico:
print(f" {op}")
# Refatorado: usa a regra do __str__ abaixo
print(self)
def __str__(self):
return f"Saldo atual: R$ {self.saldo:.2f}"
# Testando a integração
c = ContaBancaria("João", 1000)
c.depositar(500)
c.sacar(200)
c.extrato()
# O print(self) dentro do extrato chamará o __str__ automaticamente! __str__ e o extrato() se atualiza sozinho.desafio
Aplique tudo que vimos: atributos, métodos com retorno e __str__.
largura e alturaarea() e perimetro() com return__str__: "Retângulo 10x5 | Área: 50 | Perímetro: 30"e_quadrado() que retorna True se largura == alturaclass Retangulo:
def __init__(self, largura, altura):
self.largura = largura
self.altura = altura
def area(self):
return self.largura * self.altura
def perimetro(self):
return 2 * (self.largura + self.altura)
def __str__(self):
return (
f"Retângulo {self.largura}x{self.altura} | "
f"Área: {self.area()} | Perímetro: {self.perimetro()}"
) fechamento
@classmethod — quando o método pertence ao objeto vs à classe return — diferença crucial em relação a print self.metodo() __str__ — representação do objeto para o usuário (sempre retorna string) __init__, __str__, __repr__ e além para casa
Faça o máximo que conseguir e anote suas dúvidas para a próxima aula.
Exercícios: #1 ao #3
Exercícios: #4 ao #9
Exercícios: #10 ao #14
Exercícios: #15 ao #18
exercícios para casa · nível fácil
Pegue a classe Carro da aula 02 e adicione um __str__ que retorne: "[marca] [modelo] ([ano])". Teste com print().
Crie Circulo com raio. Métodos area() e perimetro() com return. __str__ com os dois valores formatados em 2 casas decimais.
Crie Temperatura com celsius. Método em_fahrenheit() que retorna a conversão (C × 1.8 + 32). __str__ exibindo ambas as unidades.
exercícios para casa · nível médio
Refaça a ContaBancaria do exercício da aula, agora com __repr__ que exibe ContaBancaria('nome', saldo). Teste os dois no terminal.
Crie Produto com nome, preco. Método aplicar_desconto(pct) que retorna o preço após desconto. __str__ com preço original e após desconto.
Evoluir o Aluno da aula 02: adicionar __str__ que exibe nome, média (via calcular_media()) e situação (via situacao()).
Crie Veiculo com modelo, combustivel (litros). Métodos abastecer(litros) e viajar(km) (gasta 0.1 L/km, usa append no histórico). __str__ com modelo e combustível atual.
Crie Placar com time_a e time_b (pontos em 0). Métodos gol_a(), gol_b() e vencedor() (retorna nome ou "Empate"). __str__ com placar.
Crie Contador com valor (inicia em 0). Métodos incrementar(), decrementar() (não vai abaixo de 0) e resetar(). __str__ com o valor atual.
exercícios para casa · nível difícil
Implemente a ContaBancaria completa: inclua um atributo de classe taxa_manutencao (ex: 5.00) e um @classmethod para alterá-lo. No extrato(), use o __str__ refatorado e mostre como a alteração da taxa afeta todas as instâncias criadas.
Crie Fila com lista interna. Métodos entrar(item) (adiciona ao final), sair() (remove o primeiro), proximo() e esta_vazia(). __str__ mostrando o conteúdo.
Crie Turma com lista de alunos (Aluno da aula 02). Métodos matricular(), media_turma(), melhor_aluno() e __str__ com resumo completo.
Crie Produto com nome, preco, categoria. Adicione @classmethod criar_promocional(cls, nome, preco) que cria um produto na categoria "Promoção" com preço reduzido em 20%.
Crie Playlist com nome e lista de músicas. Métodos adicionar, remover e embaralhar() (use import random no topo e random.shuffle(self.musicas)). O __str__ deve exibir o nome da playlist e o total de faixas.
exercícios para casa · nível avançado
Crie Livro com titulo, autor, disponivel=True e __str__. Crie Biblioteca com adicionar(), emprestar(titulo), devolver(titulo) e listar_disponiveis().
Evolua a calculadora da aula 01 para uma classe com historico. Cada operação registra um texto descritivo na lista. Método ver_historico() exibe tudo. @classmethod limpar_tudo() reseta a instância.
Crie Carrinho com lista de Produto. Métodos adicionar, remover e total().
Dica Avançada: No método total(), use um for para percorrer a lista e acessar o .preco de cada produto. O __str__ deve listar os nomes dos itens e o valor final.
Crie Disciplina com nome e lista de alunos (objetos da classe Aluno). Métodos matricular(), media_disciplina() (percorre os alunos e calcula a média geral) e listar_aprovados(). Use @classmethod para criar uma disciplina com nome padrão.
Vamos aprender a proteger os dados dos nossos objetos — atributos privados com _ e __, properties com @property e validações no setter.