Desafio Python
Ordenação com dataclass e campo calculado
Enunciado
Crie uma dataclass Retangulo com campos largura (float) e altura (float). A classe deve ser ordenável (order=True) e ter um campo calculado area que não é passado no construtor, mas calculado após a inicialização (use __post_init__). O campo area não deve participar da ordenação nem da igualdade. Crie uma lista de retângulos, ordene-a e imprima. Além disso, mostre que dois retângulos com mesma largura e altura são iguais, independentemente da área (que será igual de qualquer forma).
Requisitos
- Usar @dataclass(order=True)
- Definir campo area com field(init=False, compare=False) e calculá-lo em post_init
- Ordenar uma lista de retângulos e imprimir
- Demonstrar igualdade entre retângulos com mesmas dimensões
Código inicial
from dataclasses import dataclass, field
# Defina a dataclass Retangulo aqui
# Crie lista, ordene e imprima
# Compare dois retângulos iguais
Saída esperada
Retangulo(largura=2.0, altura=3.0, area=6.0)
Retangulo(largura=1.0, altura=5.0, area=5.0)
Retangulo(largura=3.0, altura=1.0, area=3.0)
Iguais? True
Ver dica
O campo area deve ser declarado com field(init=False, compare=False) e atribuído em post_init.
Mostrar solução
from dataclasses import dataclass, field
@dataclass(order=True)
class Retangulo:
largura: float
altura: float
area: float = field(init=False, compare=False)
def __post_init__(self):
self.area = self.largura * self.altura
# Criando retângulos
r1 = Retangulo(2.0, 3.0)
r2 = Retangulo(1.0, 5.0)
r3 = Retangulo(3.0, 1.0)
# Ordenando (usa largura e depois altura)
retangulos = [r1, r2, r3]
for r in sorted(retangulos):
print(r)
# Igualdade ignora area (mas area é igual para mesmas dimensões)
r4 = Retangulo(2.0, 3.0)
print(f'Iguais? {r1 == r4}')
Passo a passo
- Importamos
dataclassefield. - Decoramos
Retangulocom@dataclass(order=True): isso gera métodos de comparação como__lt__,__le__, etc., baseados nos campos na ordem de declaração. - Declaramos
larguraealturacomo campos normais. - Declaramos
areacomfield(init=False, compare=False):init=Falsesignifica que não aparece no__init__;compare=Falseexclui da ordenação e igualdade. - Definimos
__post_init__, que é chamado após o__init__automático, para calculararea. - Criamos três retângulos.
- Ordenamos a lista com
sorted(), que usará__lt__gerado, comparando primeirolargura, depoisaltura. - Imprimimos cada retângulo; o
__repr__incluiareaporque é um campo. - Criamos
r4igual ar1e comparamos: comoareanão participa da comparação, são iguais.
Por que funciona
order=True instrui a dataclass a gerar métodos de ordenação baseados nos campos que participam da comparação (todos, exceto os com compare=False). O campo area é calculado dinamicamente em __post_init__, garantindo que esteja sempre correto. init=False evita que o usuário precise passá-lo.
Erros comuns
- Esquecer
compare=Falseemarea: isso faria com que a ordenação considerassearea, o que pode não ser desejado. - Não usar
field(init=False): o campo apareceria no construtor, exigindo um valor. - Tentar modificar
areaapós a criação: se a classe não for frozen, é possível, mas quebra a consistência. Se for frozen,__post_init__não pode atribuir (a menos que useobject.__setattr__).
Outra forma de resolver
Poderia usar @property para area em vez de campo, mas aí não apareceria no __repr__ e não seria um campo de dataclass.
Saída esperada
Retangulo(largura=2.0, altura=3.0, area=6.0)
Retangulo(largura=1.0, altura=5.0, area=5.0)
Retangulo(largura=3.0, altura=1.0, area=3.0)
Iguais? True