Coletânea Python do ZERO às Redes Neurais Artificiais
Sobreposição de membros
Um dos cuidados que devemos ter ao manipular nossas classes em suas
hierarquias e heranças é o fato de apenas realizarmos sobreposições quando de fato queremos alterar/sobrescrever um determinado dado/valor/método dentro da mesma.
Em outras palavras, anteriormente vimos que o interpretador do Python realiza a chamada leitura léxica do código, ou seja, ele lê linha por linha (de cima para baixo) e linha por linha (da esquerda para direita).
Dessa forma, podemos reprogramar alguma linha ou bloco de código para que na sequência de sua leitura/interpretação o código seja alterado. Por exemplo:
Inicialmente criamos a classe Pessoa, dentro de si um método construtor que recebe um nome como atributo de classe. Também é definida uma Acao1 que por sua vez por meio da função print( ) exibe uma mensagem.
Em seguida é criada uma classe de nome Jogador1 que herda tudo de Pessoa e por sua vez, apenas tem um método Acao2 que exibe também uma determinada mensagem. Por fim é criado uma classe SaveJogador1 que herda tudo de Jogador1 e de Pessoa.
Trabalhando sobre essa cadeia de classes, criamos uma variável de nome p1 que instancia SaveJogador1 e passa como parâmetro ‘Fernando’, pela hierarquia destas classes, esse parâmetro alimentará self.nome de Pessoa.
Por meio da função print( ) passando como parâmetros p1.nome o retorno é: Fernando
Da mesma forma, instanciando qualquer coisa de dentro de qualquer classe da hierarquia, se não houver nenhum erro de sintaxe tudo será executado normalmente.
Neste caso o retorno será:
Fernando está dormindo
Fernando está comendo
Por fim, partindo para uma sobreposição de fato, note que agora em SaveJogador1 criamos um método de classe de nome Acao1, dentro de si uma função para exibir uma determinada mensagem.
Repare que Acao1 já existia em Pessoa, mas o que ocorre aqui é que pela cadeia de heranças SaveJogador1 criando um método Acao1 irá sobrepor esse método já criado anteriormente.
Em outras palavras, dada a hierarquia entre essas classes, o interpretador irá considerar pela sua leitura léxica a última alteração das mesmas, Acao1 presente em SaveJogador1 é a última modificação desse método de classe, logo, a função interna do mesmo irá ser executada no lugar de Acao1 de Pessoa, que será ignorada.
Nesse caso o retorno será:
Fernando está acordado (a última instrução atribuída a Acao1)
Fernando está comendo
Outra funcionalidade que eventualmente pode ser utilizada é a de,
justamente executar uma determinada ação da classe mãe e posteriormente a sobrescrever, isso é possível por meio da função reservada super( ).
Esta função em orientação a objetos faz com que seja respeitada a hierarquia de classe mãe / super classe em primeiro lugar e posteriormente as classes filhas / sub classes.
Neste caso, primeiro será executada a Acao1 de Pessoa e em seguida ela será sobrescrita por Acao1 de SaveJogador1.
O retorno será:
Fernando está dormindo (Acao1 de Pessoa)
Fernando está acordado (Acao1 de SaveJogador1)
Fernando está comendo
Avançando com nossa linha de raciocínio, ao se trabalhar com heranças deve-se tomar muito cuidado com as hierarquias entre as classes dentro de sua ordem de leitura léxica.
Raciocine que o mesmo padrão usado no exemplo anterior vale para qualquer coisa, até mesmo um método construtor pode ser sobrescrito, logo, devemos tomar os devidos cuidados na hora de usar os mesmos.
Também é importante lembrar que por parte de sobreposições, quando se trata de heranças múltiplas, a ordem como as classes são passadas como parâmetro irá influenciar nos resultados. Ex:
Apenas como exemplo, repare que foram criadas 4 classes, Pessoa, Acao1, Acao2 e SaveJogador1 respectivamente, dentro de si apenas existe um método de classe designado a exibir uma mensagem.
Para esse exemplo, o que importa é a forma como SaveJogador1 está herdando características de Acao1 e Acao2, como dito anteriormente, essa ordem ao qual as classes são passadas como parâmetro aqui influenciará os resultados da execução do código.
Nesse exemplo, SaveJogador1(Acao1, Acao2), o retorno será: Sistema pronto para uso
Exatamente a mesma estrutura anterior, porém com ordem inversa, SaveJogador1(Acao2, Acao1), o retorno será: Desligando o sistema
Apenas fazendo um adendo, caso estes tópicos ainda gerem alguma dúvida para você. Uma forma de diferenciarmos a forma como tratamos as interações entre classes dentro do Python é a seguinte:
Associação: Se dá quando uma classe usa outro ou algum objeto de outra.
Agregação: Se dá quando um ou mais objetos de classe é compartilhado, usado por duas ou mais classes (para que não seja necessário programar esse atributo para cada uma delas).
Composição: Se dá quando uma classe é dona de outra pela interligação de seus atributos e a forma sequencial como uns dependem dos outros.
Herança: Se dá quando estruturalmente um objeto é outro objeto, no sentido de que ele literalmente herda todas características e funcionalidades do outro, para que o código fique mais enxuto.