Curso de Python / Criar módulos e reutilizar código com import

Um módulo permite reutilizar código Python por meio de import, começando frequentemente com um arquivo .py. A importação procura e inicializa o módulo, em vez de simplesmente copiar seu texto; por isso, os nomes dos arquivos e as instruções executadas no nível do módulo fazem diferença.

Separar a função reutilizável do programa que a chama

Neste exercício, expense_math.py contém apenas a função de cálculo, enquanto app.py faz a chamada e mostra o resultado. Crie uma pasta de prática nova e salve os dois arquivos nela, com codificação UTF-8. Uma função que retorna um valor em vez de apenas imprimi-lo pode ser usada por diferentes programas sem repetir a definição.

import expense_math associa o nome do módulo ao programa, permitindo chamar expense_math.total(...). Outra forma, from expense_math import total, associa diretamente o nome da função, que então pode ser chamada como total(...). Escolha nomes que deixem a origem do cálculo clara e evite substituir sem perceber um nome já usado no arquivo.

Para módulos importados com a sintaxe comum, use nomes de identificador, como expense_math, com sublinhados em vez de hífens. Evite nomes como json.py ou csv.py em arquivos do projeto: eles podem ser encontrados no lugar de módulos da biblioteca padrão e fazer chamadas conhecidas falharem.

Criar e executar os dois arquivos completos

Conteúdo completo de expense_math.py:

def total(amounts):
    return sum(amounts)

Conteúdo completo de app.py:

import expense_math

print(expense_math.total([3500, 8000, 2500]))

Abra o terminal na pasta que contém esses dois arquivos, selecione o ambiente virtual do projeto se estiver usando um e execute:

python app.py

A saída esperada é uma linha com 14000, a soma de 3500, 8000 e 2500. Não é necessário instalar pacotes externos. Em macOS ou Ubuntu sem ambiente virtual, use python3 app.py se o seu interpretador for chamado python3.

A relação entre arquivo principal e arquivo auxiliar também pode ser representada assim:

practice/
  main.py
  helper.py

Esse esquema usa nomes genéricos: main.py seria o programa principal e helper.py seu auxiliar. Não crie esses arquivos adicionais para o exercício; os nomes reais continuam sendo app.py e expense_math.py, e a importação deve corresponder exatamente ao auxiliar.

Entender busca, inicialização e cache

Ao executar um arquivo de script no modo habitual, sua pasta participa da busca de módulos. É por isso que o auxiliar colocado ao lado de app.py pode ser encontrado. O diretório de trabalho também influencia caminhos relativos usados por um programa, mas não é a mesma coisa que a pasta do script: executar o caminho absoluto de app.py a partir de outra pasta não implica, por si só, que esse auxiliar deixará de ser encontrado. Modos de execução e opções de isolamento podem mudar as condições de busca.

Se ocorrer ModuleNotFoundError, confira a grafia da importação, o nome e a extensão real do arquivo, a organização das pastas e o interpretador selecionado. Um arquivo salvo como expense_math.py.txt não corresponde ao módulo esperado. Se outro módulo parecer ter sido carregado, examine seu atributo __file__, quando disponível, para identificar a origem. Antes de alterar sys.path ou copiar arquivos para uma instalação global, corrija a estrutura e a forma de execução do projeto. O tutorial de módulos e caminhos de busca explica essas relações.

As instruções no nível do módulo são executadas na primeira importação normal daquele módulo num processo. Uma definição def cria a função; já uma chamada print() nesse nível produz saída imediatamente. Por isso, um auxiliar não deve iniciar entrada interativa, gravações ou outras ações apenas por ser importado. Coloque o trabalho em funções e decida explicitamente onde chamá-las.

Módulos já carregados normalmente são reutilizados a partir de sys.modules. Importar de novo o mesmo nome no mesmo processo não significa executar tudo novamente. Ao alterar o código durante esta prática, termine a execução anterior e execute o programa em um processo novo. O sistema de importação documenta a procura, a criação e o cache dos módulos.

Testar reutilização e evitar dependências circulares

  1. Em app.py, altere somente 8000 para 9000. Execute novamente e confira 15000. A função no outro arquivo permanece igual. Restaure 8000 e confirme 14000.
  2. No fim de expense_math.py, fora da função e sem indentação, acrescente temporariamente print("helper imported"). Execute app.py num processo novo: deve aparecer helper imported antes de 14000. A mensagem significa “auxiliar importado” e foi produzida durante a importação.
  3. Acrescente uma segunda linha import expense_math em app.py, antes da impressão da soma. Execute novamente: a mensagem do auxiliar continua aparecendo uma única vez nessa execução, pois o segundo import reutiliza o módulo carregado.
  4. Retire a mensagem do auxiliar e a importação duplicada. Execute outra vez e confirme que só aparece 14000. Preserve o auxiliar sem impressões para reutilizá-lo sem mensagens inesperadas.

Se dois módulos importam um ao outro e solicitam nomes ainda não definidos durante a inicialização, uma importação circular pode falhar com referência a um módulo parcialmente inicializado. Nem toda referência circular falha imediatamente, mas esse acoplamento torna a ordem de execução difícil de acompanhar. Uma solução frequente é extrair o cálculo comum para um terceiro módulo do qual ambos dependam, sem que ele importe os programas que o usam.

Ao investigar uma importação, leia a última linha da exceção e também o trecho que aponta o arquivo carregado. Um nome de módulo desconhecido sugere busca ou instalação; um atributo esperado ausente pode indicar arquivo local com nome conflitante, inicialização incompleta ou nome de função incorreto. Diferencie essas causas antes de instalar pacotes ou mudar caminhos.