Coletânea Python do ZERO às Redes Neurais Artificiais
@property, @getters e @setters
Certamente em seus estudos de Python básico, você deve ter reparado
que uma das particularidades mais interessantes dessa linguagem é o fato da mesma ter muita coisa automatizada poupando nosso tempo na construção de certas estruturas de código.
Diferentemente de outras linguagens onde é necessário declarar o
escopo, a visibilidade, o tipo de variável, entre outras coisas manualmente, Python já nos oferece de a partir da primeira linha de código nos focar no código em si.
Sem sombra de dúvidas este é um dos maiores atrativos desta linguagem de programação tanto para iniciantes quanto para programadores que estão migrando de outras linguagens.
Automatizar certos processos não necessariamente significa que não temos o controle de tais parâmetros de nosso código, muito pelo contrário, é perfeitamente possível trabalhar em cima dessas estruturas e de forma simples, também pelo fato de que certas aplicações até terão como requisito alguma configuração interna definida de forma manual.
Em outros momentos vimos que podemos, por exemplo, tanto na programação estruturada quanto orientada à objetos, definir a visibilidade de um certo objeto ou função por meio de “_” ou “__”.
Para certas situações, podemos fazer algo parecido em nossos métodos de classe por meio de decoradores “@” como nossos conhecidos @staticmethod e @classmethod, assim como os que veremos a seguir.
Apenas relembrando, em Python temos uma série de palavras reservadas ao sistema assim como símbolos que indicam para nosso interpretador um determinado comportamento de um bloco de código.
Existe uma boa variedade de decoradores que podem ser consultados na documentação Python, aqui vamos nos ater aos mais comuns que são @property, @getter e @setter.
Outra coisa a ser mencionada já neste momento, tenha em mente que basicamente a aplicação mais comum destes decoradores são em estruturas de código onde se faz necessário o uso de alguma estrutura de validação. Realizaremos algo equivalente a um sistema validador porém aplicado diretamente como método de uma classe.
Dentro dessa lógica, basicamente ao colocar o decorador @property nosso interpretador já sabe que para aquele bloco de código existem estruturas com configurações e validadores definidos manualmente. @getter por sua vez funcionará como a função que irá obter um certo dado/valor a ser validado, e @setter será a função que irá realizar as devidas conversões de tipos de dados e os validar.
Um último adendo, o uso de decoradores internamente tem o poder de modificar a ordem da leitura dos métodos de classe.
Em outras palavras, apesar de nosso interpretador possuir regras quanto sua leitura léxica, quando criado algum decorador em meio ao código ele recebe prioridade de leitura e execução.
Partindo para prática, vamos supor que estamos criando um simples sistema de cadastro de produtos de uma loja, onde os funcionários tem acesso a um breve cadastro apenas especificando o nome e o preço de um determinado item e também a uma simples função que aplica um desconto ao item.
Para isso inicialmente criamos nossa classe Produto, dentro de si é criado um método construtor __init__ que simplesmente recebe um nome e um preco, aqui apenas por conversão já definido manualmente como 0.
Em seguida são criados os objetos referentes a nome e preco.
Na sequência é criado o método de classe aplica_desconto( ) que por sua vez receberá um percentual. Essa função simplesmente pega o valor atribuído a preco e aplica uma simples fórmula de desconto.
Até aqui nada de novo, inclusive se os usuários usarem o programa como é esperado, não existirão erros em nenhum dos processos.
Porém, lembre-se que uma boa prática de programação é tentar prever as situações onde o usuário pode explorar alguma função de forma errada, e a partir disso gerar sistemas de validação que contornem qualquer exceção cometida pelo usuário.
Nesse caso, uma das coisas mais comuns seria um usuário repassar o valor do item em um tipo de dado diferente. Por exemplo, ao invés dos 99 (int) o mesmo cadastrar ‘99’(string). É em cima deste tipo de situação que criaremos nossas estruturas de validação, nesse caso, por meio de @getters e @setters.
Criando os validadores, inicialmente colocamos nosso decorador @property para o método de classe preco( ), que por sua vez simplesmente retornará _preco.
Na sequência é criado nosso @setter, onde é criado o decorador @preco.setter para o método de classe preco( ), que agora recebe um preco_validado.
Repare que estamos criando virtualmente duas funcionalidades em cima de um método de classe, hora ele se comportará como estrutura para captação dos dados/valores a serem validados, hora ele se comportará como o validador de tais dados.
Em seguida, dentro de nosso @setter, é criada uma estrutura condicional onde se o dado/valor atribuído a preco_validado for do tipo string, o mesmo será convertido para float.
Aqui apenas para construir algo mais didático também é feita a conversão sintática por meio da função replace( ), supondo que os caracteres especiais R$ devem ser eliminados.
Por fim, o valor de _preco é atualizado com o valor de preco_validado.
A partir disso podemos cadastrar nossos produtos com os referentes preços, independentemente da maneira como o usuário digitar o preço, internamente antes mesmo desse valor ser atribuído para preco ele será validado como número do tipo float.
E o retorno para cada função print( ).