Desafio Python
Carrinho de compras com itens e total
Enunciado
Implemente duas classes: Produto (com nome e preco) e Carrinho (com uma lista de itens). O carrinho deve ter adicionar(produto, quantidade=1), remover(nome) e total() que soma preco * quantidade de cada item. Guarde os itens como uma lista de tuplas (produto, quantidade). Imprima o total formatado com duas casas decimais.
Requisitos
Produtotem atributos de instâncianomeepreco.Carrinho.adicionaraceita umProdutoe uma quantidade (padrão 1).Carrinho.remover(nome)remove o item cujo produto tem aquele nome; se não existir, levantaValueError.Carrinho.total()retorna a soma depreco * quantidadede todos os itens.
Código inicial
class Produto:
def __init__(self, nome, preco):
pass
class Carrinho:
def __init__(self):
pass
def adicionar(self, produto, quantidade=1):
pass
def remover(self, nome):
pass
def total(self):
pass
carrinho = Carrinho()
carrinho.adicionar(Produto("Caneta", 2.50), 4)
carrinho.adicionar(Produto("Caderno", 15.00))
carrinho.adicionar(Produto("Borracha", 1.20), 2)
carrinho.remover("Borracha")
print(f"Total: R$ {carrinho.total():.2f}")
Saída esperada
Total: R$ 25.00
Ver dica
Guarde os itens como (produto, quantidade) em self.itens. Em remover, itere sobre a lista e use enumerate para achar o índice; del self.itens[i] remove.
Mostrar solução
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
class Carrinho:
def __init__(self):
# lista de tuplas (produto, quantidade)
self.itens = []
def adicionar(self, produto, quantidade=1):
if quantidade <= 0:
raise ValueError("quantidade deve ser positiva")
# se o produto já existe, soma a quantidade
for i, (p, q) in enumerate(self.itens):
if p.nome == produto.nome:
self.itens[i] = (p, q + quantidade)
return
self.itens.append((produto, quantidade))
def remover(self, nome):
for i, (p, _) in enumerate(self.itens):
if p.nome == nome:
del self.itens[i]
return
raise ValueError(f"produto não encontrado: {nome}")
def total(self):
return sum(p.preco * q for p, q in self.itens)
carrinho = Carrinho()
carrinho.adicionar(Produto("Caneta", 2.50), 4)
carrinho.adicionar(Produto("Caderno", 15.00))
carrinho.adicionar(Produto("Borracha", 1.20), 2)
carrinho.remover("Borracha")
print(f"Total: R$ {carrinho.total():.2f}")
Passo a passo
Produtoguardanomeeprecocomo atributos de instância no__init__.Carrinho.__init__criaself.itens = [], uma lista vazia exclusiva de cada carrinho.- Em
adicionar, validamosquantidade > 0para evitar entradas inválidas. - Percorremos
self.itenscomenumerate; se o produto já existe (mesmonome), somamos a quantidade e retornamos. - Se não encontramos, adicionamos a tupla
(produto, quantidade)ao final da lista. removerprocura pelo nome; ao achar, usadel self.itens[i]e sai; se não achar, levantaValueError.totalusa uma generator expression dentro desumpara multiplicarpreco * quantidadede cada item.- O
printformata o resultado com:.2f, exibindo duas casas decimais.
Por que funciona
Cada Carrinho tem sua própria lista itens, porque ela é criada em __init__ e acessada via self. Isso é o oposto de colocar itens = [] no corpo da classe, que criaria uma lista compartilhada entre todos os carrinhos — bug clássico. Os métodos operam sobre self.itens, então cada objeto mantém seu estado isolado. Produto e Carrinho colaboram por composição: o carrinho contém produtos.
Erros comuns
- Definir
itens = []no corpo da classe: todos os carrinhos compartilham a mesma lista e itens vazam entre eles. Corrija comself.itens = []no__init__. - Em
remover, esquecer oreturnapósdelpode causarIndexErrornuma iteração seguinte. Usereturnimediatamente. - Comparar produtos com
==sem definir__eq__faz o Python comparar identidades; por isso comparamos porp.nomeaqui. - Esquecer
raise ValueErrorquando o produto não existe faz a função retornarNonesilenciosamente, escondendo erros.
Outra forma de resolver
Use um dicionário mapeando nome para (produto, quantidade), o que torna busca e remoção O(1):
self.itens = {} # nome -> (produto, quantidade)
Preferível quando o carrinho é grande e a busca por nome é frequente; a lista é mais simples e preserva a ordem de inserção.
Saída esperada
Total: R$ 25.00