Property Decorators Avançados
Parte da seção Object Oriented Programming do Journey de Python da Coddy — lição 31 de 64.
Decoradores de propriedade avançados fornecem um controle mais sofisticado sobre o acesso a atributos, incluindo propriedades computadas, deleters e gerenciamento completo de propriedades.
Aqui está um exemplo de propriedades computadas que derivam valores de outros atributos:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)Use propriedades computadas como atributos comuns:
rect = Rectangle(5, 3)
print(rect.area) # 15 - calculado automaticamente
print(rect.perimeter) # 16 - calculado automaticamenteCrie uma propriedade com getter, setter e deleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0Use a funcionalidade completa da propriedade:
temp = Temperature()Use o setter com validação:
temp.temperature = 25
print(temp.temperature) # 25
# temp.temperature = -300 # Levantaria ValueErrorUse o deleter:
del temp.temperature
print(temp.temperature) # 0Crie um exemplo mais complexo com uma pontuação de jogo:
class Player:
def __init__(self, name):
self.name = name
self._score = 0
self._level = 1
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if value >= 0:
self._score = value
self._level = (value // 1000) + 1
else:
raise ValueError("Score cannot be negative")
@score.deleter
def score(self):
print(f"Resetting {self.name}'s progress")
self._score = 0
self._level = 1
@property
def level(self):
return self._level
player = Player("Alice")
player.score = 2500
print(f"Score: {player.score}, Level: {player.level}") # Pontuação: 2500, Nível: 3
del player.score
print(f"Score: {player.score}, Level: {player.level}") # Pontuação: 0, Nível: 1Saída:
15
16
25
Resetting temperature to 0
0
Score: 2500, Level: 3
Resetting Alice's progress
Score: 0, Level: 1Ponto Chave: Decoradores de propriedade avançados permitem propriedades computadas (calculadas a partir de outros dados), exclusão de propriedades com @property.deleter e controle total sobre a obtenção, definição e exclusão de atributos. Isso cria interfaces intuitivas enquanto mantém uma forte validação de dados e encapsulamento.
Desafio
MédioNeste desafio, você implementará uma classe Rectangle com encapsulamento adequado e validação de propriedades.
rectangle.py- Este é o arquivo que você precisa editar, contendo comentários TODO para guiar sua implementaçãodriver.py- Contém cenários de teste extensivos (não modifique)
- Implemente atributos privados para
_widthe_height - Crie propriedades para
widtheheightcom validação (devem ser positivos)- Lance mensagens de ValueError apropriadas conforme especificado nos TODOs
- Importante: Verifique se o valor é menor ou igual a 0 e, em seguida, lance o erro (isso garante um comportamento consistente)
- Implemente propriedades somente leitura para
areaeperimeter - Crie uma propriedade
dimensionscom funcionalidades de getter, setter e deleter conforme descrito nos TODOs- Importante: No setter, use a sintaxe de desempacotamento de tupla:
width, height = dimensions
- Importante: No setter, use a sintaxe de desempacotamento de tupla:
Folha de consulta
Decoradores de propriedade avançados fornecem controle sofisticado sobre o acesso a atributos com propriedades computadas, deleters e gerenciamento completo de propriedades.
Propriedades Computadas:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)Propriedade Completa com Getter, Setter e Deleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0Uso:
# Propriedades computadas
rect = Rectangle(5, 3)
print(rect.area) # 15
print(rect.perimeter) # 16
# Funcionalidade completa de propriedade
temp = Temperature()
temp.temperature = 25 # Usa o setter
print(temp.temperature) # Usa o getter
del temp.temperature # Usa o deleterExperimente você mesmo
from rectangle import Rectangle
# Manipulador de casos de teste
test_case = input()
# Teste de funcionalidade básica
if test_case == "default_test":
rect = Rectangle(5, 3)
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
# Testar a propriedade dimensions
print(f"Dimensions: {rect.dimensions}")
rect.dimensions = (10, 8)
print(f"New area: {rect.area}")
# Testar validação
try:
rect.width = -2
except ValueError as e:
print(f"Validation error: {e}")
# Testar deletador
del rect.dimensions
print(f"After reset: {rect.dimensions}")
# Teste com valores zero
elif test_case == "zero_values":
try:
rect = Rectangle(0, 5)
except ValueError as e:
print(f"Error creating rectangle: {e}")
try:
rect = Rectangle(5, 0)
except ValueError as e:
print(f"Error creating rectangle: {e}")
# Teste com valores negativos
elif test_case == "negative_values":
rect = Rectangle(5, 3)
original_dimensions = rect.dimensions
try:
rect.dimensions = (5, -3)
except ValueError as e:
print(f"Error setting dimensions: {e}")
print(f"Dimensions after failed update: {rect.dimensions}")
print(f"Original dimensions preserved: {rect.dimensions == original_dimensions}")
# Teste com valores grandes
elif test_case == "large_values":
rect = Rectangle(1000000, 2000000)
print(f"Large rectangle area: {rect.area}")
print(f"Large rectangle perimeter: {rect.perimeter}")
# Teste com valores de ponto flutuante
elif test_case == "float_values":
rect = Rectangle(3.5, 2.75)
print(f"Dimensions: {rect.dimensions}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
rect.dimensions = (1.1, 2.2)
print(f"New area with float dimensions: {rect.area}")
# Teste com erros de tipo
elif test_case == "type_errors":
try:
rect = Rectangle("5", 3)
except Exception as e:
print(f"Type error during creation: {type(e).__name__}: {e}")
rect = Rectangle(5, 3)
try:
rect.dimensions = 10 # Não é uma tupla
except Exception as e:
print(f"Type error setting dimensions: {type(e).__name__}: {e}")
# Testar múltiplas operações de propriedade
elif test_case == "property_operations":
rect = Rectangle(5, 10)
print(f"Initial - Width: {rect.width}, Height: {rect.height}, Area: {rect.area}")
rect.width = 8
print(f"After width change - Width: {rect.width}, Area: {rect.area}")
rect.height = 6
print(f"After height change - Height: {rect.height}, Area: {rect.area}")
rect.dimensions = (12, 9)
print(f"After dimensions change - Dimensions: {rect.dimensions}, Area: {rect.area}")
del rect.dimensions
print(f"After reset - Dimensions: {rect.dimensions}, Area: {rect.area}")
# Testar casos extremos de validação de propriedade
elif test_case == "validation_edge_cases":
rect = Rectangle(5, 3)
try:
rect.width = 0
except ValueError as e:
print(f"Zero width error: {e}")
# Valor positivo muito pequeno deve ser aceito
rect.height = 0.0001
print(f"Small height accepted: {rect.height}")
print(f"Area with small height: {rect.area}")
# Testar múltiplos retângulos
elif test_case == "multiple_rectangles":
rect1 = Rectangle(5, 3)
rect2 = Rectangle(10, 2)
rect3 = Rectangle(4, 4)
print(f"Rectangle 1 - Area: {rect1.area}, Perimeter: {rect1.perimeter}")
print(f"Rectangle 2 - Area: {rect2.area}, Perimeter: {rect2.perimeter}")
print(f"Rectangle 3 - Area: {rect3.area}, Perimeter: {rect3.perimeter}")
# Modificar cada retângulo
rect1.width = 7
rect2.height = 5
rect3.dimensions = (6, 6)
print(f"After modifications:")
print(f"Rectangle 1 - Dimensions: {rect1.dimensions}")
print(f"Rectangle 2 - Dimensions: {rect2.dimensions}")
print(f"Rectangle 3 - Dimensions: {rect3.dimensions}")
# Testar desempenho com muitas operações
elif test_case == "performance_test":
rect = Rectangle(5, 5)
# Realizar muitas operações de propriedade
for i in range(1000):
rect.width = i % 10 + 1 # Valores 1-10
rect.height = i % 5 + 1 # Valores 1-5
area = rect.area # Acessar propriedade computada
perimeter = rect.perimeter # Acessar propriedade computada
dims = rect.dimensions # Acessar getter de propriedade
print(f"Final state after 1000 operations:")
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosO Parâmetro selfMétodosAtributosMétodo Construtor (__init__)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Função super()Sobrescrita de MétodoHerança MúltiplaOrdem de Resolução de MétodosRecapitulação - Hierarquia de Funcionários7Métodos Especiais
Introdução aos Métodos MágicosSobrecarga de OperadoresMétodos Mágicos de ContêinerRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução a Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy2Decoradores
Introdução aos DecoradoresDecorador de PropriedadeDecorador de Método EstáticoDecorador de Método de Classe5Polimorfismo
Sobrescrita de Método RevisitadaDuck TypingClasses e Métodos AbstratosDesign de InterfacesRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição vs HerançaMixinsMétodos Estáticos e de ClasseDecoradores de ClasseGerenciadores de Contexto11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Propriedades de Classe
Variáveis de Instância vs de ClasseDecoradores de PropriedadeAtributos PrivadosRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Membros Públicos, Protegidos e PrivadosModificadores de AcessoOcultação de InformaçãoProperty Decorators AvançadosRecapitulação - Sistema de Registro de Alunos12Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário