Módulos em Python

modpython_1-abertura.png

Conforme um programa aumenta em funcionalidade e/ou complexidade também crescerá em tamanho e se transformando em uma longa e tediosa coleção de linhas de código de difícil manutenção. Neste caso¹ é de bom grado dividi-lo em partes menores — e deixar que a própria linguagem se encarregue de agrupar durante a execução — que o deixarão mais simples de se trabalhar, compreender e também de reutilizar seus componentes em outros projetos.

Em Python eles são chamados de módulos e são geralmente usados para expandir as capacidades da linguagem, carregar funcionalidades e, claro, também permitir que seu programa possa ser segmentado em unidades menores  e assim não virar uma tripa! 😀

(¹) Ou mesmo funcionalidades implementadas em um programa que seriam úteis em um outro mas que simplesmente copiá-la não parece das soluções mais elegantes.

Funções em módulos

Começando com um exemplo bastante simples, ou seja, uma função dentro do mesmo programa que a utiliza:

#!/usr/bin/env python3
# exemplo 1
def media(a, b):
    return (a + b)/2.0

print(media(3, 2))

Daí, só testar:

$ ./1_funcao_dentro_do_programa.py 
2.5

Porém, pode ser uma boa ideia colocar esta função fora do corpo do programa. Seja porque fica mais fácil de trabalhar em arquivos pequenos ou apenas pela possibilidade de poder utilizar esta função em outros programas.

Então a rotina vai para um novo arquivo, o “media.py”:

def media(a, b):
    return (a + b)/2.0

E o programa passa por uma pequena alteração:

#!/usr/bin/env python3
# exemplo 2
from media import media
print(media(3, 2))

A sintaxe do comando, apesar de parecer estranha, serve apenas para dizer que do módulo “media.py” seja importada a função definida como media() para o programa.

Objetos em módulos

A mesma lógica se aplica às classes, como neste exemplo:

#!/usr/bin/env python3
# exemplo 3
class Calculos(object):
    a=0
    b=0
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def media(self):
        return (self.a + self.b)/2.0

calculos = Calculos(3, 2)
print(calculos.media())

Onde a parte relacionada ao objeto propriamente dito vai para “calculos.py” e o programa principal alterado para importá-lo:

#!/usr/bin/env python3
# exemplo 4
from calculos import Calculos

calculos = Calculos(3, 2)
print(calculos.media())

Como no exemplo anterior a linha fica estranha também mas ao menos fica  fácil de identificar que neste caso o que é carregado é um objeto.

Módulos em diretórios

Já que se começou a deixar o código mais organizado, que tal colocar o módulo em um diretório específico do projeto, ajudando a separar melhor aquilo que efetivamente é seu programa dos demais arquivos.

A primeira coisa a fazer é criar um diretório para armazená-los e para lá copiar lá o “calculos.py”:

$ mkdir meus_modulos
$ cp calculos.py meus_modulos

Depois é alterar um pouco o programa:

#!/usr/bin/env python3
# exemplo 5
from meus_modulos import calculos

calculos = calculos.Calculos(3, 2)
print(calculos.media())

Neste caso o módulo é explicitamente importado para dentro do programa e mantendo seu próprio escopo, o “calculos”. Para deixá-lo dentro do escopo dos módulos basta acrescentar o arquivo “__init__.py” dentro de “./meus_modulos” com o seguinte conteúdo:

# __init__.py
from calculos import Calculos

Aí uma pequena modificação no programa:

#!/usr/bin/env python3
# exemplo 6
import meus_modulos

calculos = meus_modulos.Calculos(3, 2)
print(calculos.media())

E assim tornar a carga das classes implícita e assim usar somente um import meus_modulos dentro do código.

Disponibilizando o módulo

Claro, se as rotinas de uso geral foram separadas do resto do programa é porque há o interesse de usá-las em outros programas. Mas como fazê-lo? Copiar o diretório a cada novo projeto (e não esquecer de sincronizá-lo)? Criar um link simbólico² para o diretório?

A solução, melhor, soluções são simples e consistem em dizer ao Python onde os módulos estão e isto pode ser feito de duas formas razoavelmente distintas. Uma modificando o código e a outra não.

Com alteração no código

Inicialmente retirando o código do diretório de trabalho.

$ cp -r meus_modulos /tmp
$ cp 7_modulo_carregado_em_tmp.py ~
$ cd

E incluindo o diretório do módulo no PATH da linguagem:

#!/usr/bin/env python3
# exemplo 7
import sys
sys.path.append('/tmp')

import meus_modulos

calculos = meus_modulos.Calculos(3, 2)
print(calculos.media())

E “pronto”, ele procurará o por meus_modulos também em “/tmp”:

$ ./7_modulo_carregado_em_tmp.py 
Traceback (most recent call last):
 File "./7_modulo_carregado_em_tmp.py", line 6, in <module>
 import meus_modulos
 File "/tmp/meus_modulos/__init__.py", line 4, in <module>
 from calculos import Calculos
ImportError: No module named 'calculos'

Ué? Por que não funcionou? Acontece que o “__init__.py” também está fazendo a carga de um módulo e ele também precisará ser ensinado sobre um novo caminho a procurar, o lugar onde ele próprio se encontra:

# __init.py__
import sys
sys.path.append('/tmp/meus_modulos')
from calculos import Calculos

E o “problema” fica resolvido:

$ ./7_modulo_carregado_em_tmp.py 
2.5

Aliás, removendo o arquivo “__init__.py” e utilizando apenas from meus_modulos import calculos para explicitamente carregar a classe o programa também funcionaria.

Sem alteração no código

Mais uma vez retirando o código do diretório de trabalho:

$ cp 6_modulo_em_outro_diretorio_2.py ~

Mas desta vez criando uma variável de ambiente, a PYTHONPATH, com o caminho necessário para se encontrar os módulos:

export PYTHONPATH="$( pwd ):$( pwd )/meus_modulos"

Aqui usei o comando pwd para pegar o diretório corrente de um jeito bem mais fácil, no mundo real utilize o caminho correto.

Então, sem alterar nada no código, executá-lo:

$ cd ~$ ./6_modulo_em_outro_diretorio_2.py 
2.5

(²) Sempre é bom lembrar que há sistemas operacionais “atrasados” que não possuem este recurso. 🙂

E para terminar…

A documentação do Python contém mais detalhes sobre a forma de se construir módulos dentro da linguagem e vale a pena sua leitura. Foi lá que acabei achando a informação sobre o uso da variável de ambiente PYTHONPATH para aumentar a quantidade de lugares onde ele procura os módulos para carregar.

E os arquivos usados aqui estão no repositório Git do blog!

 

Anúncios

Um comentário sobre “Módulos em Python

  1. Pingback: Módulos em Python | Zion Eco

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s