3
respostas

Qual a real utilidade do @property

Boa noite, Assisti as aulas mais de uma vez mas não ficou claro pra mim a real utilidade dos decoradores @property e @nome.setter por exemplo. Apenas chamar um método como se fosse um atributo (Sem os parênteses)? No começo do curso aprendemos que não deveríamos alterar o valor do atributo de um objeto diretamente (conta.nome= Jose) e, portanto, deveríamos proteger os atributos e métodos com o underscore. No fim do curso, com a utilização dos decoradores, acabamos fazendo o que deveríamos supostamente evitar (conta.nome=jose).

3 respostas

Olá Stefano! Tudo certo? Espero que sim. 🙂

Desculpe pela demora no retorno.

O @property é um decorador interno do Python que faz o intermédio entre os atributos (variáveis) do objeto que estamos criando e seus métodos de alteração e visualização.

Quando usamos o @property, não estamos acessando os atributos diretamente, mas através de um método que estamos definindo. Porém, para o usuário que está acessando os objetos pelo terminal, criamos uma "ilusão" de que os atributos estão sendo acessados diretamente. Isso oferece uma sintaxe de código mais flúida ao usuário.

Existem 3 maneiras gerais de se fazerem operações nos atributos de um objeto. A seguir eu vou lista-las utilizando um script específico como exemplo ...

Alterando o atributo do objeto de forma direta.

# Objeto que guarda os dados da temperatura de um ambiente
class Celsius:
    def __init__(self, temperatura):
        if temperatura < -273.15:
            print("Temperatura abaixo de -273.15 não é possível.")
        else:
            self.temperatura = temperatura

    # Método que converte graus celsius para fahrenheit
    def para_fahrenheit(self):
        return (self.temperatura * 1.8) + 32



# Criando um novo objeto...
casa = Celsius(25)

# Retornando a temperatura unsando o Getter
print(casa.temperatura)

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

# Testando a condição do Setter
casa.temperatura = -300

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

Nesse script acima, perceba que ao criar o objeto conseguimos definir alguns atributos e até mesmo definir uma condição para esse atributo. Porém, essa condição só se aplica ao inicializar o objeto. Um vez inicializado, os atributos podem ser mudados diretamente pelo usuário, sem restrições. Os motivos desse forma de script de orientação a objeto não ser muito utilizada são claras devido à falta de controle sobre os atributos e pouca praticidade ao necessitar fazer alterações no código.

Utlizando os métodos Getters e Setters.

# Objeto que guarda os dados da temperatura de um ambiente
class Celsius:
    def __init__(self, temperatura):
        self.set_temperatura(temperatura)

    # Método que converte graus celsius para fahrenheit
    def para_fahrenheit(self):
        return (self.__temperatura * 1.8) + 32

    # Método Getter
    def get_temperatura(self):
        return self.__temperatura

    # Método Setter
    def set_temperatura(self, valor):
        if valor < -273.15:
            print("Temperatura abaixo de -273.15 não é possível.")
        else:
            self.__temperatura = valor


# Criando um novo objeto...
casa = Celsius(25)

# Retornando a temperatura unsando o Getter
print(casa.get_temperatura())

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

# Testando a condição do Setter
casa.set_temperatura(-300)

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

Através dessa forma, nós podemos tornar os atributos privados e utilizar os métodos Getter e Setter para fazer as operações que desejamos. Através do Setter podemos, até mesmo estabelecer uma condição para a alteração de um atributo. A utilização dos Getters e Setters é o padrão na orientação de objetos presentes em linguagens como o Java e, apesar de funcionar também no Python, temos uma maneira especial de atingirmos o mesmo resultado no Python ...

Utilizando o decorador Property

# Objeto que guarda os dados da temperatura de um ambiente
class Celsius:
    def __init__(self, temperatura):
        self.__temperatura = temperatura

    # Método que converte graus celsius para fahrenheit
    def para_fahrenheit(self):
        return (self.__temperatura * 1.8) + 32

    # Usando o @property
    @property
    def temperatura(self):
        return self.__temperatura

    # Fazendo o Setter com o @property
    @temperatura.setter
    def temperatura(self, valor):
        if valor < -273.15:
            print("Temperatura abaixo de -273.15 não é possível.")
        else:
            self.__temperatura = valor


# Criando um novo objeto...
casa = Celsius(25)

# Retornando a temperatura unsando o @property
print(casa.temperatura)

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

# Testando a condição do @temperatura.setter
casa.temperatura = -300

# Usando o método para_fahreheit
print(casa.para_fahrenheit())

O decorador @property é uma função interna do Python desenhada especialmente para desempenhar o pepel dos Getters e Setters.

Para utiliza-lo, basta definir um atributo com o @property anterior a um método de mesmo nome do atributo e para executar as operações é só utilizar seus métodos internos que incluem: @<nome do atributo>.getter (facultativo após a declaração do atributo), @<nome do atributo>.setter e, o extra, @<nome do atributo>.deleter.

Dentre as vantagens da utilização do @property estão:

  • Uma busca mais dinâmica na memória pelos atributos internos de cada objeto;
  • Não precisar invocar um método para a alteração dos atributos. Isso pode ser feito como se o atributo estivesse sendo alterado diretamente, simplificando a sintaxe de código. casa.set_temperatura(<nova temperatura>) x casa.temperatura = <nova temperatura>

Espero ter ajudado! Quaisquer dúvidas, estou à disposição. 😉

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.Bons Estudos!