Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> python

Dominando Decorator @property do Python: Getters & Setters Limpos e Compatíveis

Dominando Decorator @property do Python

Descubra como decorator built-in @property do Python permite escrever getters e setters concisos e manuteníveis mantendo sua API backward compatible.

Decorator @property do Python é ferramenta poderosa para encapsular acesso a atributos. Permite definir lógica customizada que executa sempre que atributo é lido ou escrito, sem forçar chamadores a mudar seu código. Nas seções a seguir percorreremos exemplo real — lidando com conversões de temperatura — mostraremos como impor constraints e explicaremos por que @property é solução idiomática.


Classe Sem Getters e Setters

Suponha que precisamos classe simples que armazena temperatura em Celsius e converte para Fahrenheit:

class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature
    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

Usar é direto:

# Criar novo objeto
human = Celsius()
# Definir temperatura
human.temperature = 37
# Ler temperatura
print(human.temperature)
# Converter para Fahrenheit
print(human.to_fahrenheit())

Saída

37 98.60000000000001

Resultado ponto flutuante é esperado devido à representação binária de decimais. Ao inspecionar human.__dict__, verá que Python armazena valor em entrada de dicionário simples:

>>> human.__dict__
{'temperature': 37}

Adicionando Constraints com Getters e Setters

Objetos reais frequentemente precisam validação. Por exemplo, temperaturas não podem cair abaixo do zero absoluto (-273.15 °C). Forma direta é esconder atributo e expor métodos getter/setter explícitos:

class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)
    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32
    # getter
    def get_temperature(self):
        return self._temperature
    # setter
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value

Agora classe impõe limite inferior, mas qualquer código existente acessando obj.temperature deve ser atualizado para chamar obj.get_temperature() e obj.set_temperature(val). Grande refatoração para codebases grandes.

Além disso, variáveis "privadas" do Python são apenas convenção de nomenclatura — _temperature ainda pode ser acessado diretamente, quebrando encapsulamento. É aqui que @property brilha.


Usando Classe property

Python oferece classe property que amarra funções getter e setter a nome de atributo:

class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature
    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32
    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature
    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value
    # expor como property
    temperature = property(get_temperature, set_temperature)

Com essa configuração, código abaixo se comporta exatamente como classe simples original, mas com validação nos bastidores:

human = Celsius(37)
print(human.temperature)  # dispara getter
print(human.to_fahrenheit())  # usa getter internamente
human.temperature = -300  # dispara setter e levanta ValueError

Saída

Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible

Note como código acessando temperature permanece inalterado; apenas implementação subjacente ganhou validação.

Dica: Dado real vive em _temperature; temperature é apenas interface conveniente e segura.


Decorator @property

Enquanto classe property funciona, sintaxe de decorator do Python oferece forma mais limpa e legível de alcançar mesmo resultado. Decorator automaticamente cria objeto property e anexa getter e setter ao nome do atributo.

class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature
    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32
    @property
    def temperature(self):
        print("Getting value...")
        return self._temperature
    @temperature.setter
    def temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273 is not possible")
        self._temperature = value

Uso permanece o mesmo:

human = Celsius(37)
print(human.temperature)
print(human.to_fahrenheit())
# Tentando definir temperatura inválida
try:
    Celsius(-300)
except ValueError as e:
    print(e)

Saída

Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible

Usar @property mantém namespace limpo, elimina necessidade de nomes separados para getter/setter, e é padrão recomendado para maioria desenvolvedores Python.

python

  1. Dominando Tipos de Dados em Python: Guia Prático
  2. Dominando Operadores em Python: Guia Completo
  3. Dominando a Declaração Pass em Python: Guia Prático
  4. Dominando Argumentos de Funções em Python: Parâmetros Posicionais, Nomeados e Padrão
  5. Dominando Dicionários em Python: Criação, Manipulação e Técnicas Avançadas
  6. Dominando Herança em Python: Conceitos, Sintaxe e Exemplos Práticos
  7. Dominando Sobrecarga de Operadores em Python: Guia Prático
  8. Dominando Iteradores em Python: Como Funcionam e Como Criar os Seus
  9. Closures em Python Explicados: Como Funções Aninhadas Capturam Variáveis
  10. Dominando Decorator @property do Python: Getters & Setters Limpos e Compatíveis