Categorias
Introdução à Programação para Bioinformática com Biopython

Princípios da orientação a objetos

Capítulo 8

Este conteúdo faz parte do livro “Introdução à Programação para Bioinformática com Biopython“. Você pode adquirir a versão impressa desse livro aqui ou a versão para Kindle aqui. Para nos citar, consulte este link.

Até agora falamos de elementos básicos da linguagem Python, tais como strings, valores inteiros, laços de repetição e funções. A partir deste capítulo novos conceitos serão acrescentados visando familiarizar você, leitor, a termos usados no meio computacional. Esses métodos permitem a criação de aplicações com maior manutenibilidade e extensibilidade, facilitando o reuso dos códigos criados.

No prefácio deste livro conceituamos “paradigma” como um sinônimo de metodologia ou a representação de um padrão. Partindo deste princípio, até agora utilizamos o chamado “paradigma estrutural”, que consiste em uma sequência de comandos interpretados linearmente, um após o outro. No paradigma estrutural um dos únicos elementos de organização, ou reaproveitamento de código, são as funções. Agora, veremos o mundo da programação orientada a objetos (POO), que visa abstrair elementos do mundo real, como objetos que interagem entre si. Iniciaremos conceituando classes, objetos, atributos, métodos e herança no que tange a POO.

Conceituando os elementos da POO

Classe: é um conjunto de atributos e funções que serve como modelo para gerar objetos. Podemos modelar classes, por exemplo, para representar proteínas, DNA, os mamíferos, etc.

Objeto: em ciência da computação diz-se que um objeto é uma instância de uma classe. Assim sendo, um objeto é um indivíduo em particular que possui todas as características comuns aos outros indivíduos da mesma classe, porém com valores diferentes para seus atributos. Em um exemplo simples temos uma classe “Proteína” que agrupa as características de uma proteína como: sua sequência de aminoácidos, localização do sitio ativo, função, etc. Um objeto (instância) da classe “Proteína” poderia ser uma “globulina”, que possui características (valores dos atributos) distintas da “insulina” por exemplo.

Atributo: os atributos de uma classe são as características do elemento que a classe representa. Retomando nosso exemplo da classe “Proteína”, temos como atributos da mesma sua sequência de aminoácidos, localização do sitio ativo, função, peso molecular, solubilidade, etc.

Método: são as ações que um dado objeto pode realizar ao interagir com outros objetos. Como exemplo, no pacote BioPython, que estudaremos a partir do próximo capítulo, podemos encontrar a classe “MaxEntropy” que possui um método chamado “calculate” cuja função é calcular a entropia máxima.

Herança: no contexto de orientação a objetos, a herança consiste em uma classe “filha” que herda as características da classe “mãe”. Além dos atributos (características) e métodos (ações), que a classe mãe possui, a classe filha possui informações mais específicas relacionadas a apenas um subgrupo da classe mãe. A analogia mais comumente usada é a da filogenia, onde um filo ancestral possui características mais abrangentes em relação aos seus filhos. Assim, por exemplo, se temos uma classe “Mamíferos”, que possui características gerais a todos os mamíferos, como a presença de glândulas mamárias, podemos ter as classes filhas “Humano” e “Foca”, que possuem características específicas do seu subgrupo, como por exemplo, o atributo “locomoção” para humanos (bípedes) seria diferente do que para focas (nadadoras).

Representação de classes em código

O código abaixo visa exemplificar cada um dos elementos conceituados acima. Usaremos classes que estão disponíveis no pacote Biopython.

class Entity(object):
    """
    Classe que contém as características comuns às \
classes Structure, Model, Chain and Residue.
    """
    def __init__(self, id):
        self.id=id
        self.full_id=None
        self.parent=None
        self.child_list=[]
        self.child_dict={}
        # Dicionário que mantém as propriedades adicionais
        self.xtra={}
 
    # Métodos especiais
 
    def __len__(self):
        "Retorna o número de filhos"
        return len(self.child_list)
 
    def __getitem__(self, id):
        "Retorna o filho correspondente ao id passado."
        return self.child_dict[id]
 
    def has_id(self, id):
        """Retorna verdadeiro(True) se existir um \
filho com o id passado."""
        return (id in self.child_dict)
 
    def get_level(self):
        """Retorna o nível na hierarquia.
        A - atom
        R - residue
        C - chain
        M - model
        S - structure
        """
        return self.level
 
class Chain(Entity):
    def __init__(self, id):
        self.level="C"
        Entity.__init__(self, id)
 
    def get_atoms(self):
        for r in self:
            for a in r:
                yield a

O código acima nos mostra duas classes: “Entity”, que é uma classe mãe criada para agrupar as características comuns às classes filhas, e “Chain”, uma classe filha que possui características específicas de uma cadeia polipeptídica. O primeiro método da classe “Entity” é o “__init__” que é o método chamado “construtor” da classe. Este método é chamado durante a instanciação da classe.

Observe que o método “__init__” possui dois parâmetros: self e id. O parâmetro self é usado, por convenção, para informar que a função é um método de uma classe, servindo também para que a instância do novo objeto criado seja passada para o método. O parâmetro id é utilizado para fazer a distinção entre objetos da classe e deve ser passado durante a criação (instanciação) do objeto.

Foi convencionado que o uso de dois caracteres underline, no início e no fim de um método (“__init__”, “__len__”, “__getitem__”, etc.), informa que esse método é especial e não deve ser alterado. Esse tipo de declaração se aproxima aos métodos privados (private) encontrados em outras linguagens de programação, como por exemplo, Java.

A classe possui também outros métodos, como por exemplo, o get_level( ), que serve para retornar, como descrito na documentação, o nível na hierarquia. Esse e outros métodos são criados para representar as ações que os objetos desta classe podem realizar.

Podemos notar ainda que no corpo do método “__init__”, existem algumas variáveis precedidas da palavra self: id, full_id, parent, child_list, child_dict, xtra. Essas variáveis são os atributos dos objetos da classe “Entity”. Estes atributos podem ser inicializados na instanciação da classe (como no caso do id que é passado como parâmetro), como podem ser inicializados com valores vazios para que sejam posteriormente preenchidos.

Por fim, encontramos a classe Chain, que é uma classe filha da classe Entity. Por ser uma classe filha, a classe Chain herda todas as características (atributos e métodos) da classe Entity. A primeira diferença pode ser encontrada logo na declaração da classe: “class Chain(Entity)”. Após a palavra class, colocamos o nome da classe e, entre parênteses, colocamos o nome da classe mãe. Podemos encontrar ainda em Python a chamada “herança múltipla”, que consiste em uma classe filha que pode possuir mais de uma classe mãe. Um exemplo de cabeçalho para definição de uma classe com herança múltipla seria:

class Filha(Mae1, Mae2, Mae3): 
    # ...

Podemos observar que a classe Chain, declarada no início desse capítulo, possui mais um atributo (level). Esse atributo é característico da classe Chain, não sendo encontrado nos objetos da classe Entity, por exemplo. A classe também possui seus próprios métodos (como o get_atoms( ) que retorna todos os átomos da cadeia), que poderão ser acessados por objetos da mesma.

Diferenças da POO em Python para outras linguagens

Toda a linguagem Python é orientada a objetos, ou seja, todos os elementos da linguagem, com exceção dos operadores aritméticos (+, -, =, *, etc.), são objetos de uma classe. Por exemplo, um número decimal armazenado em uma variável do tipo float (ex.: 50.0), que nas demais linguagens é um tipo primitivo, em Python é considerado um objeto da classe float. Essa classe possui diversos métodos, dentre eles, o método “is_integer()”, que retorna True caso o número passado seja inteiro, ou retorna False caso seja do tipo float. Observe o exemplo no quadro abaixo:

#Criação de uma variável float
n = 50.0
 
#vamos  verificar se este valor é int
print(n.is_integer())
 
# Irá imprimir True
n = 50.5
 
print(n.is_integer())
# Irá imprimir False.

O mesmo ocorre com uma string, por exemplo. Observe o seguinte código:

a = "Meu Texto"
print(a.upper())
#Irá imprimir "MEU TEXTO"

Note que a variável “a” possui um método “upper” que retorna uma string com todas as letras em maiúsculo. É importante frisar que a chamada do método “upper” vai retornar uma nova string com o seu texto em maiúsculo, porém não altera o conteúdo anterior da variável “a” que continua o mesmo.

Como dito anteriormente, não temos por objetivo aprofundar em programação orientada a objetos, entretanto consideramos relevante apresentar alguns conceitos básicos sobre POO. Nos capítulos a seguir, iremos começar a trabalhar com a biblioteca desenvolvida por terceiros Biopython. Acreditamos que os conceitos apresentados até agora foram suficientes para que o usuário possa compreender melhor sobre o funcionamento básico de pacotes, módulos e classes da biblioteca Biopython. A partir desse ponto, algumas funções que possamos considerar básicas podem não ser explicadas detalhadamente. Se possuir dúvidas, sugerimos que volte aos capítulos anteriores e os releia. Sugerimos ainda que consulte a internet. A documentação oficial do Python pode ser obtida em: <https://www.python.org/doc/>.

Quer aprender mais? Conheça nossos cursos profissionalizantes à partir de R$19,99:

Livro Introdução à Programação para Bioinformática com Biopython

Capítulo 1
Introdução ao Python

Capítulo 2
Comandos condicionais

Capítulo 3
Laços de repetição

Capítulo 4
Trabalhando com strings

Capítulo 5
Listas

Capítulo 6
Manipulando arquivos

Capítulo 7
Funções

Capítulo 8
Princípios da orientação a objetos

Capítulo 9
Introdução ao Biopython

Capítulo 10
Sequências

Capítulo 11
BLAST

Capítulo 12
PDB

Capítulo 13
Visualização de dados em Python

Capítulo 14
Outras coisas interessantes que se pode fazer com Biopython

Capítulo 15
Hierarquia do Biopython

Por favor, nos cite:

MARIANO, D. C. B.; BARROSO, J. R. P. M. ; CORREIA, T. S. ; de MELO-MINARDI, R. C. . Introdução à Programação para Bioinformática com Biopython. 3. ed. North Charleston, SC (EUA): CreateSpace Independent Publishing Platform, 2015. v. 1. 230p .

Por Diego Mariano

Doutor em Bioinformática pela Universidade Federal de Minas Gerais com atuação na área de ciência de dados e aprendizado de máquina aplicados ao aperfeiçoamento de enzimas usadas na produção de biocombustíveis. Mestre em Bioinformática, também pela UFMG, atuando na área de desenvolvimento de sistemas Web para montagem de genomas. Atualmente realiza estágio pós-doutoral no Departamento de Ciência da Computação da UFMG com foco em desenvolvimento de sistemas Web para Bioinformática, análise exploratória e visualização de dados. Tem conhecimentos nas linguagens: PHP, JavaScript, Python, R, Perl, HTML, CSS e SQL.