Aula 8: Propriedades (A Forma "Pythônica")

Simplificando o acesso a atributos com decoradores.

O Que Você Vai Aprender

Nesta aula, você explorará as Propriedades em Python, uma forma elegante e "pythônica" de gerenciar o acesso a atributos. Você aprenderá a usar os decoradores `@property` e `@.setter` para transformar métodos em atributos, permitindo que você adicione lógica de getter e setter sem alterar a forma como os atributos são acessados externamente.

✨ `@property` (Getter Pythônico)

Transformar um método em um atributo acessível.

✏️ `@.setter` (Setter Pythônico)

Adicionar lógica de modificação para uma propriedade.

Conceito: Propriedades

Em Python, as Propriedades oferecem uma maneira elegante de controlar o acesso a atributos de uma classe. Em vez de usar explicitamente métodos `get_` e `set_`, você pode usar decoradores para fazer com que os métodos de getter e setter se comportem como atributos normais.

O Decorador `@property`

Ao usar `@property` acima de um método, ele se torna um "getter". Isso significa que você pode acessá-lo como se fosse um atributo (sem parênteses), e o método será executado.

class MinhaClasse:
    def __init__(self, valor):
        self._valor_interno = valor

    @property
    def valor(self): # Este método agora é acessado como 'objeto.valor'
        print("Acessando o valor...")
        return self._valor_interno

O Decorador `@.setter`

Para definir um "setter" para a sua propriedade, você usa o decorador `@.setter` sobre outro método (com o mesmo nome da propriedade). Este método será chamado quando você tentar atribuir um valor ao "atributo" da propriedade.

class MinhaClasse:
    # ... (código do @property acima)

    @valor.setter # 'valor' é o nome da propriedade definida com @property
    def valor(self, novo_valor): # Este método é chamado quando 'objeto.valor = x'
        if novo_valor > 0:
            print(f"Definindo o valor para: {novo_valor}")
            self._valor_interno = novo_valor
        else:
            print("Valor inválido!")

Exemplo Prático: Classe `Produto` com Propriedade `preco`

Vamos aplicar as propriedades à classe `Produto` para controlar o acesso e a modificação do seu preço, aplicando um desconto ao obter o valor e validando a entrada ao definir.

Implementação da `Produto` com `@property` e `@preco.setter`

class Produto:
    def __init__(self, nome, preco):
        self.nome = nome
        self._preco = preco # Atributo protegido que armazena o valor real

    @property # Getter para a propriedade 'preco'
    def preco(self):
        # Lógica para obter o preço, ex: aplicar um desconto
        print("Acessando o preço (com possível desconto)...")
        return self._preco * 0.9 # Exemplo de 10% de desconto

    @preco.setter # Setter para a propriedade 'preco'
    def preco(self, novo_preco):
        print(f"Tentando definir o preço para: {novo_preco}")
        if novo_preco >= 0:
            self._preco = novo_preco
            print("Preço atualizado com sucesso!")
        else:
            print("Erro: O preço não pode ser negativo.")

# Exemplo de uso:
# meu_produto = Produto("Camiseta", 100.0)

# Acessando a propriedade (chama o getter @property)
# print(f"Preço da camiseta: R${meu_produto.preco:.2f}") # Saída: Acessando o preço... Preço da camiseta: R$90.00

# Definindo a propriedade (chama o setter @preco.setter)
# meu_produto.preco = 120.0 # Saída: Tentando definir o preço para: 120.0 \n Preço atualizado com sucesso!
# print(f"Novo preço: R${meu_produto.preco:.2f}") # Saída: Acessando o preço... Novo preço: R$108.00

# Tentando definir um valor inválido
# meu_produto.preco = -10 # Saída: Tentando definir o preço para: -10 \n Erro: O preço não pode ser negativo.

Simulador: Propriedade `preco` da Classe `Produto`

Crie um produto e experimente acessar e modificar seu preço usando as propriedades. Observe as mensagens do console.

Objeto `Produto` Simulado

Nome: Caneta, Preço Base (interno): R$10.00

Este simulador usa a lógica da classe `Produto` apresentada para demonstrar o funcionamento das propriedades.

Interagir com a Propriedade `preco`