terça-feira, 26 de março de 2013

Encapsular campos em Python 3.x

Encapsulamento de dados é um recurso presente em linguagens que seguem o paradigma orientado a objetos. Esse recurso tem como objetivo restrigir o acesso direto a informação, ou seja, ele protege informações que não devem ser alteradas em qualquer parte do programa. Com isso podemos entender que quem está de fora apenas sabe que o serviço é realizado mas não sabe como o serviço é implementado.

Certamente quando começamos a programar orientado a objetos não vemos os benefícios que o encapsulamento de dados nos proporciona, pois, a primeira vista ele só serve para gerar mais linhas de código.

Hoje vou falar como encapsular dados na linguagem de programação Python versão 3.x. Se você já programou em alguma linguagem .Net (Visual Basic, C#) não sentirá grandes mudanças, porém, se você é um programador Java sentirá uma certa estranheza quando ler o código.

Bom sem mais demora vamos conhecer mais um pouquinho da linguagem Python e sua implementação diferente em POO.

Protegendo minhas variáveis dos Noobs

Na minha opinião o encapsulamento de dados existe, porém, não garante a total segurança do seu código. Antes de você me chamar de louco vou explicar, se você é um programador Java e ficou muito ofendido com o que eu disse ... me desculpe essa não foi a intenssão! Mas Sr.Programador Java, seu código não está seguro só porque o Sr. usa o modificador de acesso private em suas variáveis de instância, se alguém quiser saber quais são as variáveis presentes em determinadas classes de seu sistema ele pode fazer isso utilizando a própria API do Java a nossa querida Reflection. Logicamente que trabalhar com essa API não é algo trivial, porém, pense duas vezes antes de desafiar um nerd dizendo que seu código está 100% seguro.

Em Python a história também não é diferente, se alguém quiser saber quais variáveis sua classe tem essa pessoa vai acabar descobrindo de um jeito ou de outro. Por isso que a ideia principal de Python é que tudo seja public e somente o necessário, seja private. Muitas vezes quando estamos aprendendo POO o pessoal costuma dizer: "Grande parte das vezes sua classe terá atributos de instância privado e métodos públicos". Mais nem sempre é assim, podemos realmente ter variáveis em nossas classes que não precisam serem private.

Bom, se você está certo que precisa ter variáveis private em sua classe e não quer que ela seja acessível fora da classe onde ela foi especificada, então você terá que informar primeiramente que ela será private, para que o interpretador Python saiba disso. Para dizer que um atributo de instância é private em python utilizamos dois underline antes do nome da variável. Exemplo:

class Gato:
    __raca = None
    ...

Com isso dizemos ao interpretador que o atributo raça é privado. Agora temos que construir dois métodos, um para setar (setter) e outro para recuperar (getter) o valor do atributo. No python 3.x foi introduzida uma sintaxe muito elegante para realizar esse serviço. Veja:

class Gato:
    def __init__(self):
        __raca = None

    @property
    def raca(self):
        return __raca

    @raca.setter
    def raca(self, value):
        self.__raca = value

Viu como é simples? Bom o que fizemos foi definir dois métodos (em python pode-se falar função da classe), onde no primeiro definimos o getter e o segundo o definimos o setter. Observe que os dois métodos tem o mesmo nome, mas possuem anotações diferentes. A primeira anotação @property indica o método é um getter e a segunda anotação @raca.setter indica que o método é um setter,  perceba que a segunda anotação é bem diferente da primeira, nela devemos informar o nome do atributo seguido de ponto e a palavra setter.

Podemos definir que um atributo seja apenas read-only. Para fazer isso basta excluir o método setter. Veja:

class Gato:
    def __init__(self):
        __raca = None

    @property
    def raca(self):
        return __raca

Agora observe como fica natural o acesso aos atributos:

if __name__ == '__main__':
    mimo = Gato()
    megui = Gato()

    mimo.raca = 'angorá turco'
    mimo.idade = 2

    megui.raca = 'siames'
    megui.idade = 1

    print('Megui é da raça {}, e tem {} ano(s) de idade.'.format(megui.raca, megui.idade))
    print('Mimo é da raça {}, e tem {} ano(s) de idade.'.format(mimo.raca, mimo.idade))

Pessoal o post se encerra por aqui! Espero que tenham gostado de aprender um pouco mais sobre Python e veja vocês em um próximo post, até lá e BONS ESTUDOS!

6 comentários:

  1. Este comentário foi removido por um administrador do blog.

    ResponderExcluir
  2. Cara, ao invés de remover meu comentário, remova esse seu "intenssão".

    ResponderExcluir
    Respostas
    1. Opa cara assim que der tempo eu corrigo. Espero que não tenha te limitado ao entender o post todo. Obrigado!

      Excluir
    2. hehehe... Seu post é muito bom. Parabéns!

      Excluir
  3. Encapsulamento não serve para esconder quais são as váriaveis de uma classe, seriam modificadores de acesso.
    Sobre reflection, muitos dos métodos dessa API podem ser desativados, ou vc acha que consegue acessar e modificar aplicações de grandes bancos?

    ResponderExcluir
    Respostas
    1. Amigo acho que vc não entendeu a ideia do post, mas enfim vou deixar outra fonte talvez lá vc acompanhe o raciocínio por estar mais detalhado o conteúdo. Modificadores de acesso fazem parte do conceito de encapsulamento :D hehe.

      Sim é possível invadir qualquer sistema amigo, pesquise um pouco e vera que muitos sistemas de grandes bancos foram atacados e penetrados. Sem contar grandes sistemas, que vc pode achar que nunca iriam ser penetrados.

      Sobre Reflection sim vc pode desativar ela, mas isso se faz com configuração e ai vc tem que rodar no modo seguro e bla bla bla. O ponto é que isso nem sempre e feito e por ser configurável isso pode ser desfeito.

      Para vc estudar:
      http://www.devmedia.com.br/conceitos-encapsulamento-programacao-orientada-a-objetos/18702

      PS = Não vou colocar links de noticias de bancos hackeados pq cara tem muitos é só por no Google que aparece 100 paginas a mais :D

      Excluir

Novidade!!! Agora vamos ter canal no Youtube =D

Fala pessoal tudo beleza, estou sumido a correria está forte por aqui. Estou querendo dar um start em um projeto antigo que vem desde o temp...