Trilha de aprendizado · Nível 5 · Tutorial 3

Organizar módulos em pacotes locais

Organizar módulos relacionados em uma hierarquia de pacotes locais e executá-los preservando a resolução correta das importações.

  • Nível: Intermediário
  • Duração: 20 min
  • 6 passos
Organizar módulos em pacotes locais

O que você vai percorrer

  1. Criar uma hierarquia de pacotes regulares Organize módulos de relatórios em um pacote regular e um subpacote, usando arquivos __init__.py para definir a estrutura. 3 min
  2. Importar usando o nome completo do pacote Transforme posições na hierarquia de arquivos em nomes qualificados e use importações absolutas explícitas no pacote relatorios. 3 min
  3. Executar um módulo a partir da pasta correta Execute o módulo principal pelo nome qualificado com -m e reconheça como a pasta de partida determina a localização do pacote. 3 min
  4. Usar importações relativas dentro do pacote Referencie módulos próximos com pontos explícitos e execute o programa preservando o contexto do pacote. 3 min
  5. Reorganizar dependências para evitar ciclos Identifique um ciclo entre módulos, extraia configurações compartilhadas e preserve o resultado do projeto com dependências unidirecionais. 4 min
  6. Concluir e verificar o pacote local Integre um novo resumo de média, confira a direção das dependências e execute o pacote completo no contexto correto. 5 min

O que você vai aprender

  • Criar um pacote regular com __init__.py e módulos com responsabilidades relacionadas.
  • Escrever importações absolutas explícitas usando nomes qualificados de pacotes.
  • Usar importações relativas explícitas entre módulos de um mesmo pacote.
  • Executar um módulo com python -m pacote.modulo a partir da pasta adequada.
  • Reorganizar dependências simples entre módulos para evitar importações circulares.

Antes de começar

  • Separar código em módulos e usar importações explícitas
  • Controlar a execução de módulos com __name__

Passo 1 de 6

Criar uma hierarquia de pacotes regulares

Organize módulos de relatórios em um pacote regular e um subpacote, usando arquivos init.py para definir a estrutura.

Responsabilidades em níveis

Do projeto aos módulos

Você organizará um projeto chamado projeto_relatorios. Dentro dele, o pacote de topo relatorios reunirá dados e a coordenação do programa. O subpacote resumos concentrará as responsabilidades de cálculo e formatação:

  • dados.py: mantém os dados de vendas em memória.
  • principal.py: será o ponto de coordenação do programa.
  • resumos/calculos.py: realiza os cálculos.
  • resumos/formatacao.py: produz o texto do resumo.

A pasta do projeto contém o pacote, enquanto as pastas de pacote contêm módulos ou outros pacotes.

Anatomia da hierarquia

A estrutura possui quatro níveis distintos: pasta do projeto, pacote de topo, subpacote e arquivos de módulos.

Diagrama de pastas aninhadas mostrando projeto_relatorios, o pacote relatorios, o subpacote resumos e seus módulos Python.

projeto_relatorios contém o pacote relatorios; dentro dele, resumos é outro pacote.

Marque os pacotes regulares

Crie a árvore de arquivos

No seu editor, crie exatamente esta estrutura:

projeto_relatorios/
└── relatorios/
    ├── __init__.py
    ├── dados.py
    ├── principal.py
    └── resumos/
        ├── __init__.py
        ├── calculos.py
        └── formatacao.py

Crie os dois arquivos __init__.py e deixe-os completamente vazios. Eles identificam relatorios e resumos como pacotes regulares. A pasta externa projeto_relatorios é apenas a pasta do projeto e não precisa desse arquivo.

O que acontece na inicialização

Na primeira importação de um pacote em um processo, o Python executa o respectivo __init__.py. Isso também acontece quando a solicitação inicial é por um submódulo: os pacotes necessários para alcançá-lo são inicializados.

Um __init__.py vazio é suficiente para esta estrutura. Sua execução não produz efeito visível e não importa automaticamente todos os outros módulos da pasta.

Dica

Mantenha a inicialização mínima

Não use __init__.py como uma lista central de módulos. Neste projeto, mantenha os dois arquivos vazios e coloque cada responsabilidade em seu módulo próprio.

Preencha os módulos

Arquivo: relatorios/dados.py

Este módulo mantém os dados de exemplo usados ao longo do projeto.

python
VENDAS = [1200.0, 850.0, 1530.0, 990.0]

Arquivo: relatorios/resumos/calculos.py

As operações numéricas ficam no subpacote de resumos.

python
def calcular_total(valores):
    return sum(valores)


def calcular_media(valores):
    if not valores:
        return 0.0
    return calcular_total(valores) / len(valores)

Arquivo: relatorios/resumos/formatacao.py

Esta primeira versão já produz o resumo na convenção monetária que será preservada. No próximo step, o cálculo existente será conectado a ela por uma importação explícita.

python
def criar_resumo(valores):
    total = sum(valores)
    return f"Total de vendas: R$ {total:.2f}"

Arquivo: relatorios/principal.py

Por enquanto, o módulo principal contém somente a estrutura de coordenação já conhecida. As conexões entre os módulos serão acrescentadas no próximo step.

python
def main():
    pass


if __name__ == "__main__":
    main()

Confira a estrutura

Associe cada elemento

Relacione cada elemento da árvore ao seu papel no projeto.

Toque em um item e depois no par correspondente.

Passo 2 de 6

Importar usando o nome completo do pacote

Transforme posições na hierarquia de arquivos em nomes qualificados e use importações absolutas explícitas no pacote relatorios.

Do caminho de arquivo ao nome qualificado

Pontos no lugar de pastas

Na hierarquia criada, cada módulo pode ser identificado por um nome qualificado. Ele reúne pacote, subpacote e módulo, separados por pontos.

Por exemplo, o arquivo relatorios/resumos/calculos.py corresponde ao nome importável relatorios.resumos.calculos.

No nome qualificado, retire a extensão .py e troque os separadores de pasta por pontos.

A hierarquia vira um nome

Observe como cada nível da árvore participa do nome qualificado do módulo.

Diagrama da pasta relatorios, do subpacote resumos e do módulo calculos, associados ao nome relatorios.resumos.calculos.

Pacote, subpacote e módulo formam o nome qualificado relatorios.resumos.calculos.

Dica

“Absoluta” não significa caminho do computador

Uma importação absoluta começa pelo pacote de topo, como relatorios. Ela não começa por um caminho do sistema, como C:\projetos ou /home/usuario/projetos.

A forma do import define o acesso

Módulo inteiro ou nome específico

Com import relatorios.dados, o acesso mantém o nome qualificado: relatorios.dados.VENDAS.

Com from relatorios.resumos.calculos import calcular_total, a função é vinculada diretamente ao nome calcular_total. Portanto, a chamada não repete o caminho do módulo.

Exemplo

Duas formas, duas referências

import relatorios.dados
from relatorios.resumos.calculos import calcular_total

valores = relatorios.dados.VENDAS
total = calcular_total(valores)

A primeira forma preserva a origem no uso de VENDAS. A segunda permite chamar diretamente a função importada.

Atualize os módulos do projeto

Importações absolutas em arquivos completos

Mantenha os demais arquivos criados anteriormente e substitua o conteúdo dos dois arquivos abaixo. Todas as importações começam pelo pacote de topo relatorios.

Arquivo: relatorios/resumos/formatacao.py

Este módulo usa a função de cálculo pelo nome qualificado completo de sua origem.

python
from relatorios.resumos.calculos import calcular_total


def criar_resumo(valores):
    total = calcular_total(valores)
    return f"Total de vendas: R$ {total:.2f}"

Arquivo: relatorios/principal.py

O módulo principal importa o módulo dados inteiro e uma função específica de formatacao.

python
import relatorios.dados
from relatorios.resumos.formatacao import criar_resumo


def main():
    resumo = criar_resumo(relatorios.dados.VENDAS)
    print(resumo)


if __name__ == "__main__":
    main()

Complete os nomes importáveis

Importe a função

Complete a importação absoluta:

from ____ import calcular_total

Acesse a constante

Depois de import relatorios.dados, complete a expressão que obtém a constante:

valores = ____

Passo 3 de 6

Executar um módulo a partir da pasta correta

Execute o módulo principal pelo nome qualificado com -m e reconheça como a pasta de partida determina a localização do pacote.

Pasta de partida e nome do módulo

O terminal começa fora do pacote

Os arquivos permanecem como ficaram no step anterior. Para executar o programa, abra o terminal em projeto_relatorios, a pasta que contém o pacote de topo relatorios.

Use -m para pedir ao Python que localize e execute um módulo por seu nome qualificado. Portanto, o argumento é relatorios.principal: sem .py e sem separadores de pasta.

Estar dentro de relatorios não equivale a estar na pasta do projeto. Nesse caso, o Python procuraria outro pacote relatorios a partir do local inadequado.

O terminal fica na pasta externa

Diagrama com a pasta projeto_relatorios envolvendo o pacote relatorios e o módulo principal.py, enquanto o terminal está posicionado no nível da pasta externa.

O comando parte de projeto_relatorios, que contém o pacote relatorios; o módulo é localizado pelo nome relatorios.principal.

Execute pelo nome qualificado

Use o comando Python já configurado

Com o terminal aberto em projeto_relatorios, execute o comando abaixo. Se o comando de Python 3 no seu computador for python3, py ou outro, substitua apenas python; preserve -m relatorios.principal.

A opção -m localiza o módulo como parte da hierarquia de pacotes. Isso é diferente de fornecer ao interpretador um caminho de arquivo, como relatorios/principal.py.

Comando de execução

Execute somente esta linha no terminal:

shell
python -m relatorios.principal

Saída esperada

Compare a saída produzida com esta linha:

text
Total de vendas: R$ 4570.00

Atenção

Não execute de dentro de relatorios

Se o terminal estiver dentro da pasta relatorios, o mesmo comando poderá falhar com uma mensagem como No module named 'relatorios'. Volte para projeto_relatorios e repita o comando. Não altere o caminho de busca do Python para contornar o problema.

Diagnostique a localização

Escolha a combinação correta

Qual combinação executa o módulo principal deste projeto local?

Verifique no seu computador

Teste a pasta incorreta e corrija

Primeiro, entre na pasta relatorios e tente executar python -m relatorios.principal. Observe a falha de localização. Depois, volte para projeto_relatorios, repita o mesmo comando e compare o resultado com a saída esperada.

Se necessário, adapte somente o comando usado para iniciar o Python 3 no seu computador.

Relate o diagnóstico

Em qual pasta o primeiro comando foi executado, que falha de localização você observou e como corrigiu o ponto de partida? Registre também o comando bem-sucedido e a saída produzida.

Escreva pelo menos 80 caracteres (0/80).

Passo 4 de 6

Usar importações relativas dentro do pacote

Referencie módulos próximos com pontos explícitos e execute o programa preservando o contexto do pacote.

Os pontos partem do pacote do módulo

Pacote atual e pacote pai

Uma importação relativa começa com pontos e é resolvida a partir do pacote ao qual o módulo pertence:

  • Em relatorios/principal.py, from .dados import VENDAS parte de relatorios. Um ponto representa esse pacote atual.
  • Em relatorios/resumos/formatacao.py, from .calculos import calcular_total parte de relatorios.resumos.
  • Ainda em formatacao.py, from ..dados import VENDAS usaria dois pontos para subir ao pacote pai, relatorios, e então localizar dados.

O último exemplo apenas demonstra o significado de ..; não o adicione ao projeto, pois a formatação não precisa importar os dados.

De onde partem um e dois pontos

O módulo formatacao.py pertence ao subpacote relatorios.resumos. Por isso, um ponto mantém a busca nesse subpacote, enquanto dois pontos levam ao pacote pai relatorios.

Diagrama da hierarquia relatorios e resumos mostrando setas de formatacao.py para calculos.py no pacote atual e para dados.py no pacote pai.

Os pontos são interpretados pela posição do módulo na hierarquia, não pela pasta atual do terminal.

Troque as importações internas

Relativas para relações próximas

Substitua integralmente os dois arquivos abaixo. As novas importações apontam para os mesmos recursos das formas absolutas usadas anteriormente. A escolha é de clareza: nomes absolutos deixam a origem completa visível; nomes relativos podem destacar relações internas próximas. Nenhuma das duas formas precisa ser usada em todos os casos.

Arquivo: relatorios/resumos/formatacao.py

Aqui, .calculos e relatorios.resumos.calculos apontam para o mesmo módulo.

python
from .calculos import calcular_total


def criar_resumo(valores):
    total = calcular_total(valores)
    return f"Total de vendas: R$ {total:.2f}"

Arquivo: relatorios/principal.py

Como principal.py pertence a relatorios, .dados e .resumos partem desse pacote.

python
from .dados import VENDAS
from .resumos.formatacao import criar_resumo


def main():
    resumo = criar_resumo(VENDAS)
    print(resumo)


if __name__ == "__main__":
    main()

Preserve o contexto do pacote

Arquivo direto versus módulo do pacote

Com o terminal aberto em projeto_relatorios, teste primeiro a execução direta abaixo. Embora o caminho encontre o arquivo, essa forma inicia principal.py como um script isolado e não fornece automaticamente o contexto necessário para resolver .dados e .resumos.

Execução direta que falha

Execute esta linha no terminal usando o comando de Python 3 configurado no seu computador.

shell
python relatorios/principal.py

Atenção

Importação relativa sem pacote pai conhecido

A execução direta deve falhar com uma mensagem semelhante a ImportError: attempted relative import with no known parent package. Não altere sys.path nem as importações para contornar isso. Permaneça em projeto_relatorios e execute o módulo pelo nome qualificado com -m.

Execução correta no contexto do pacote

Este comando fornece o contexto de relatorios e deve produzir Total de vendas: R$ 4570.00.

shell
python -m relatorios.principal

Verifique as equivalências

Relativa e absoluta apontam para o mesmo recurso

Associe cada importação relativa à forma absoluta equivalente.

Toque em um item e depois no par correspondente.

Explique a diferença de execução

Por que python relatorios/principal.py falha com as importações relativas, enquanto python -m relatorios.principal funciona quando executado em projeto_relatorios?

Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 6

Reorganizar dependências para evitar ciclos

Identifique um ciclo entre módulos, extraia configurações compartilhadas e preserve o resultado do projeto com dependências unidirecionais.

Reconheça o ciclo

Setas mostram quem depende de quem

Em um diagrama de dependências, A → B significa que A importa B. Uma sequência que retorna ao ponto inicial forma um ciclo.

Considere uma tentativa de compartilhar a política de precisão dos relatórios. formatacao.py precisa dos cálculos, mas calculos.py tenta obter CASAS_DECIMAIS de formatacao.py. Assim, surge o ciclo:

formatacao → calculos → formatacao

Ao importar formatacao, o Python começa a executá-lo e encontra a importação de calculos. Durante a inicialização de calculos, a importação tenta acessar CASAS_DECIMAIS em um formatacao ainda parcialmente inicializado. Como esse nome ainda não foi definido, a importação pode falhar.

Dependências antes da refatoração

As duas setas entre os módulos revelam o caminho circular.

Diagrama em que formatacao aponta para calculos e calculos aponta de volta para formatacao, formando um ciclo.

A seta parte do módulo que realiza a importação. O retorno ao módulo inicial caracteriza o ciclo.

Exemplo circular: relatorios/resumos/calculos.py

Analise esta versão completa, mas não a copie para o projeto. A política de precisão é buscada no módulo de formatação.

python
from .formatacao import CASAS_DECIMAIS


def calcular_total(valores):
    return round(sum(valores), CASAS_DECIMAIS)


def calcular_media(valores):
    if not valores:
        return 0.0
    return round(
        calcular_total(valores) / len(valores),
        CASAS_DECIMAIS,
    )

Exemplo circular: relatorios/resumos/formatacao.py

A primeira instrução inicia calculos.py antes que as configurações abaixo tenham sido definidas.

python
from .calculos import calcular_total

SIMBOLO_MOEDA = "R$"
CASAS_DECIMAIS = 2


def criar_resumo(valores):
    total = calcular_total(valores)
    return (
        f"Total de vendas: {SIMBOLO_MOEDA} "
        f"{total:.{CASAS_DECIMAIS}f}"
    )

Escolha uma direção sem ciclo

Qual diagrama remove o ciclo?

Escolha a organização em que formatacao.py usa os cálculos, enquanto a política compartilhada fica em um módulo de responsabilidade específica.

Extraia as configurações compartilhadas

Refatore a direção das dependências

Crie constantes.py no subpacote relatorios/resumos e substitua integralmente calculos.py e formatacao.py pelas versões abaixo.

CASAS_DECIMAIS representa a política de precisão dos resultados do relatório, usada no cálculo e na apresentação. SIMBOLO_MOEDA também pertence às configurações desse relatório. Assim, constantes.py tem uma responsabilidade específica, em vez de ser um depósito genérico.

Neste exercício, corrigiremos a direção das dependências por extração. Mantenha os arquivos __init__.py vazios: eles não devem centralizar essas importações.

Novo arquivo: relatorios/resumos/constantes.py

As configurações compartilhadas passam a ter uma origem independente.

python
SIMBOLO_MOEDA = "R$"
CASAS_DECIMAIS = 2

Substitua relatorios/resumos/calculos.py

O módulo de cálculos consulta diretamente a política de precisão.

python
from .constantes import CASAS_DECIMAIS


def calcular_total(valores):
    return round(sum(valores), CASAS_DECIMAIS)


def calcular_media(valores):
    if not valores:
        return 0.0
    return round(
        calcular_total(valores) / len(valores),
        CASAS_DECIMAIS,
    )

Substitua relatorios/resumos/formatacao.py

A apresentação depende do cálculo e das configurações, sem receber nenhuma importação de volta.

python
from .calculos import calcular_total
from .constantes import CASAS_DECIMAIS, SIMBOLO_MOEDA


def criar_resumo(valores):
    total = calcular_total(valores)
    return (
        f"Total de vendas: {SIMBOLO_MOEDA} "
        f"{total:.{CASAS_DECIMAIS}f}"
    )

Verifique a saída preservada

Execute no contexto do pacote

Mantenha principal.py, dados.py e os arquivos __init__.py como estavam. Abra o terminal em projeto_relatorios, a pasta que contém o pacote relatorios, e execute o módulo principal.

Comando

shell
python -m relatorios.principal

Saída esperada

Compare manualmente a linha produzida. A reorganização das dependências não deve alterar o resultado.

text
Total de vendas: R$ 4570.00

Registre a refatoração

Qual foi a saída da execução? Explique por que as dependências formatacao → calculos, formatacao → constantes e calculos → constantes não formam um ciclo.

Escreva pelo menos 80 caracteres (0/80).

Passo 6 de 6

Concluir e verificar o pacote local

Integre um novo resumo de média, confira a direção das dependências e execute o pacote completo no contexto correto.

Planeje a extensão final

Novo resumo, mesma organização

Você acrescentará media.py ao subpacote relatorios/resumos. O novo módulo apresentará a média das vendas reutilizando calcular_media e as configurações de constantes.py.

A estrutura final será:

projeto_relatorios/
└── relatorios/
    ├── __init__.py
    ├── dados.py
    ├── principal.py
    └── resumos/
        ├── __init__.py
        ├── calculos.py
        ├── constantes.py
        ├── formatacao.py
        └── media.py

Mantenha os dois arquivos __init__.py vazios. As dependências devem seguir em uma única direção: os módulos de apresentação podem importar cálculos e constantes, mas estes não devem importar os módulos de apresentação.

Estrutura e dependências finais

As setas indicam quem importa quem. Nenhuma sequência retorna ao módulo de origem.

Diagrama da árvore final do pacote relatorios e das dependências unidirecionais entre principal, dados, formatacao, media, calculos e constantes.

principal coordena o programa; formatacao e media reutilizam módulos de nível mais básico, sem receber importações de volta.

Implemente as conexões

Use importações explícitas nos pontos indicados

Crie media.py com importações relativas, pois seus recursos estão no mesmo subpacote. Depois, substitua principal.py pela versão completa abaixo, que usa importações absolutas iniciadas por relatorios. Preserve os demais arquivos exatamente como ficaram no step anterior.

Novo arquivo: relatorios/resumos/media.py

O módulo recebe os dados, calcula a média e produz a segunda linha do relatório.

python
from .calculos import calcular_media
from .constantes import CASAS_DECIMAIS, SIMBOLO_MOEDA


def criar_resumo_media(valores):
    media = calcular_media(valores)
    return (
        f"Média de vendas: {SIMBOLO_MOEDA} "
        f"{media:.{CASAS_DECIMAIS}f}"
    )

Substitua relatorios/principal.py

O módulo coordenador usa os dados existentes e apresenta os dois resumos.

python
from relatorios.dados import VENDAS
from relatorios.resumos.formatacao import criar_resumo
from relatorios.resumos.media import criar_resumo_media


def main():
    print(criar_resumo(VENDAS))
    print(criar_resumo_media(VENDAS))


if __name__ == "__main__":
    main()

Execute e compare

Faça a verificação manual

Abra o terminal em projeto_relatorios, a pasta que contém o pacote relatorios. Execute o módulo principal pelo nome qualificado. Se o comando do Python 3 no seu computador for diferente, substitua somente python.

Comando

Execute esta linha no terminal.

shell
python -m relatorios.principal

Saída esperada

Compare manualmente as duas linhas produzidas pelo programa.

text
Total de vendas: R$ 4570.00
Média de vendas: R$ 1142.50

Revisão e conclusão

Registre a verificação final

Informe onde você criou o novo módulo, quais importações relativas e absolutas foram usadas, de qual pasta executou o programa, qual comando utilizou e qual saída observou. Por fim, explique por que as dependências finais não formam um ciclo.

Escreva pelo menos 120 caracteres (0/120).

Resumo

Critérios de um pacote local funcional

Use estes pontos para revisar o projeto concluído.

  • A pasta do projeto contém o pacote de topo, e cada pacote regular possui seu __init__.py.
  • As importações usam nomes absolutos ou relativos explícitos coerentes com a posição dos módulos.
  • A execução parte da pasta que contém relatorios e usa -m relatorios.principal.
  • Módulos de apresentação dependem de cálculos e constantes, sem dependências inversas que fechem um ciclo.
  • A saída final preserva o total e acrescenta a média calculada com os mesmos dados.

Pacote local concluído

Parabéns! Você concluiu: Organizar módulos em pacotes locais

Tutorial concluído! Você já consegue estruturar e executar um pacote local Python de forma coerente.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso