Atributos e métodos
Veja como objetos guardam informações e executam ações, e como métodos podem colaborar entre si.
Você já sabe criar uma classe, definir atributos no __init__ e escrever métodos básicos. Agora vamos aprofundar: veja como atributos podem ter valores padrão, como métodos podem chamar outros métodos dentro da mesma classe, e como tudo isso se encaixa em um exemplo completo.
Atributos com valor padrão
No __init__, nem todo atributo precisa vir como parâmetro. Alguns podem começar com um valor padrão fixo, independente do que for passado ao criar o objeto:
class ContaBancaria:
def __init__(self, titular, saldo_inicial):
self.titular = titular
self.saldo = saldo_inicial
self.extrato = [] # começa vazio — não é passado como parâmetro
self.ativa = True # toda conta começa ativa por padrão
O self.extrato e o self.ativa são atributos que nascem com um valor já definido. Quem cria a conta não precisa (nem pode) passá-los — eles são inicializados automaticamente.
Atributos com parâmetros opcionais
Você também pode criar parâmetros com valor padrão no __init__, tornando-os opcionais na criação do objeto:
class Produto:
def __init__(self, nome, preco, estoque=0):
self.nome = nome
self.preco = preco
self.estoque = estoque # se não informado, começa em 0
arroz = Produto("Arroz 5kg", 28.90, 150) # estoque informado
cafe = Produto("Café 500g", 18.50) # estoque não informado, começa em 0
print(arroz.estoque) # 150
print(cafe.estoque) # 0
Parâmetros com valor padrão funcionam em métodos da mesma forma que em funções comuns — eles devem sempre vir depois dos parâmetros obrigatórios.
Métodos que chamam outros métodos
Dentro de uma classe, um método pode chamar outro usando self.nome_do_metodo(). Isso é muito útil para evitar repetição e manter cada método com uma responsabilidade clara:
class ContaBancaria:
def __init__(self, titular, saldo_inicial):
self.titular = titular
self.saldo = saldo_inicial
self.extrato = []
self.ativa = True
def depositar(self, valor):
self.saldo += valor
self.extrato.append(f"+ R$ {valor:.2f}") # sempre atualiza o extrato
def sacar(self, valor):
if valor > self.saldo:
print("Saldo insuficiente.")
return
self.saldo -= valor
self.extrato.append(f"- R$ {valor:.2f}") # sempre atualiza o extrato
def saldo_disponivel(self):
return self.saldo
def exibir_extrato(self):
print(f"=== Extrato de {self.titular} ===")
for movimento in self.extrato:
print(movimento)
print(f"Saldo atual: R$ {self.saldo_disponivel():.2f}") # chama outro método!
No método exibir_extrato(), a chamada self.saldo_disponivel() acessa o resultado de outro método da mesma classe. Isso evita duplicar a lógica e deixa o código mais organizado.
Se chegar um dia em que precisamos mudar como o saldo disponível é calculado — por exemplo, descontando uma taxa — basta alterar saldo_disponivel() e exibir_extrato() continuará funcionando sem mudança.
conta = ContaBancaria("Ana Silva", 1000.00)
conta.depositar(500.00)
conta.sacar(200.00)
conta.sacar(2000.00) # Saldo insuficiente.
conta.exibir_extrato()
Saída:
Saldo insuficiente.
=== Extrato de Ana Silva ===
+ R$ 500.00
- R$ 200.00
Saldo atual: R$ 1300.00
Modificando atributos por fora da classe
Além dos métodos, você pode alterar um atributo diretamente de fora da classe:
conta = ContaBancaria("Bruno Costa", 500.00)
print(conta.titular) # Bruno Costa
conta.titular = "Bruno Costa Jr." # modificação direta
print(conta.titular) # Bruno Costa Jr.
Exemplo prático: sistema de alunos
Vamos construir uma classe completa que combina tudo que aprendemos: atributos padrão, parâmetros opcionais, métodos chamando outros métodos e múltiplos objetos:
class Aluno:
def __init__(self, nome, matricula, curso="Não informado"):
self.nome = nome
self.matricula = matricula
self.curso = curso
self.notas = [] # atributo padrão — começa sempre vazio
def adicionar_nota(self, nota):
if nota < 0 or nota > 10:
print(f"Nota inválida: {nota}. Use valores entre 0 e 10.")
return
self.notas.append(nota)
def calcular_media(self):
if not self.notas:
return 0
soma = sum(self.notas)
quantidade = len(self.notas)
media = soma / quantidade
return media
def situacao(self):
media = self.calcular_media() # chama outro método
if media >= 7:
return "Aprovado"
elif media >= 5:
return "Recuperação"
else:
return "Reprovado"
def relatorio(self):
media = self.calcular_media() # chama outro método
status = self.situacao() # chama outro método
print(f"\n=== {self.nome} ===")
print(f"Matrícula : {self.matricula}")
print(f"Curso : {self.curso}")
print(f"Notas : {self.notas}")
print(f"Média : {media:.1f}")
print(f"Situação : {status}")
Veja como relatorio() chama calcular_media() e situacao(), e como situacao() chama calcular_media(). Cada método faz uma coisa só, e eles colaboram entre si:
# Criando objetos
ana = Aluno("Ana Silva", "2026001", "Desenvolvimento Web")
bruno = Aluno("Bruno Costa", "2026002") # curso usa o valor padrão
# Adicionando notas
ana.adicionar_nota(8.5)
ana.adicionar_nota(7.0)
ana.adicionar_nota(9.0)
ana.adicionar_nota(11) # Nota inválida: 11. Use valores entre 0 e 10.
bruno.adicionar_nota(4.0)
bruno.adicionar_nota(5.5)
# Exibindo relatórios
ana.relatorio()
bruno.relatorio()
Saída:
Nota inválida: 11. Use valores entre 0 e 10.
=== Ana Silva ===
Matrícula : 2026001
Curso : Desenvolvimento Web
Notas : [8.5, 7.0, 9.0]
Média : 8.2
Situação : Aprovado
=== Bruno Costa ===
Matrícula : 2026002
Curso : Não informado
Notas : [4.0, 5.5]
Média : 4.8
Situação : Reprovado
Repare que
ana.notasebruno.notassão listas completamente independentes — cada objeto tem sua própria cópia dos atributos, mesmo quando eles nascem com o mesmo valor padrão.
O que aprendemos nesta lição
Nesta lição, você aprendeu que:
- Atributos podem ter valores padrão fixos no
__init__(comoself.notas = []), sem precisar ser passados como parâmetro. - Parâmetros do
__init__podem ser opcionais com valor padrão (comocurso="Não informado"), exatamente como em funções comuns. - Métodos podem chamar outros métodos da mesma classe usando
self.nome_do_metodo(), evitando repetição e mantendo responsabilidades separadas. - Atributos podem ser modificados diretamente de fora da classe com
objeto.atributo = novo_valor. - Cada objeto tem sua própria cópia independente dos atributos — alterar
ana.notasnão afetabruno.notas.