Curso de Python / Organizar pacotes e executar com __main__ e -m
Um pacote organiza módulos Python relacionados numa hierarquia de nomes. Colocar a execução numa função main() e chamá-la por um ponto de entrada explícito permite importar o código sem iniciar automaticamente o cálculo ou a interface do programa.
Preparar a estrutura de um pacote regular
Este exercício cria um pacote regular, identificado pelo arquivo __init__.py dentro da pasta expense_app. Existem também pacotes de espaço de nomes, que podem omitir esse arquivo; aqui usamos a estrutura explícita para manter claras a organização e a inicialização. A técnica amplia a separação de código em módulos importáveis.
Crie uma pasta de prática chamada project e, dentro dela, a pasta expense_app. Salve os três arquivos na estrutura abaixo, todos com codificação UTF-8:
project/
expense_app/
__init__.py
math_tools.py
__main__.py
Abra o terminal em project, a pasta que contém expense_app, e selecione o ambiente virtual se estiver usando um. Não entre na pasta do pacote para executar os comandos deste exercício. Não é necessário instalar dependências externas nem o próprio pacote no ambiente.
Salvar os arquivos e executar com -m
Conteúdo completo de expense_app/__init__.py:
"""Expense calculation package."""
A string de documentação significa “Pacote de cálculo de despesas”. Esse arquivo não precisa fazer cálculos nem importar a aplicação inteira. Conteúdo completo de expense_app/math_tools.py:
def total(amounts):
return sum(amounts)
Conteúdo completo de expense_app/__main__.py:
from .math_tools import total
def main():
print(total([3500, 8000, 2500]))
if __name__ == "__main__":
main()
No terminal aberto em project, execute:
python -m expense_app
A saída esperada é uma linha com 14000. Em macOS ou Ubuntu sem ambiente virtual, use python3 -m expense_app se o interpretador for chamado python3. O nome passado a -m é o nome do pacote, sem extensão .py e sem barras de caminho.
A opção -m localiza o pacote pelo mecanismo de importação e executa seu módulo __main__ com o contexto do pacote. Na importação from .math_tools import total, o ponto significa “no pacote atual”. Executar python expense_app/__main__.py como um arquivo solto não fornece esse mesmo contexto e, neste exemplo, causa ImportError na importação relativa. A documentação da opção de linha de comando -m explica a forma de localizar e executar o alvo.
Controlar a chamada de main e os efeitos da importação
Quando esse módulo é executado como programa principal, seu __name__ é "__main__" e a condição final chama main(). Quando ele é importado como expense_app.__main__, seu nome é "expense_app.__main__" e a condição é falsa. A função fica disponível, mas a conta não é impressa automaticamente.
main é uma convenção de nome, não uma função que Python chama automaticamente em qualquer arquivo. Neste código, a chamada está escrita explicitamente dentro do if. O arquivo especial __main__.py e a condição baseada em __name__ têm papéis relacionados, mas distintos, descritos na documentação de __main__ e pontos de entrada.
A condição não impede outras instruções no nível do módulo de serem executadas durante a importação. A própria importação de math_tools e a definição de main() acontecem; uma chamada de impressão ou gravação escrita fora da condição também aconteceria. Manter cálculos e efeitos dentro de funções adia essas ações até uma chamada explícita.
Encontrar módulos e encontrar arquivos de dados são problemas diferentes. Um caminho relativo de dados é normalmente resolvido a partir do diretório de trabalho do processo, não automaticamente a partir da pasta do pacote. Este exemplo não lê dados de disco; se a aplicação passar a fazê-lo, escolha caminhos recebidos por argumento ou um mecanismo adequado de recursos do pacote, em vez de presumir uma pasta de início fixa.
Verificar execução e importação separadamente
Sem alterar os arquivos, execute o comando abaixo também a partir de project:
python -c "import expense_app.__main__; print('imported')"
Deve aparecer somente imported, que significa “importado”. Se 14000 aparecer antes da mensagem, procure uma chamada de main() ou outro cálculo fora da condição final, inclusive em módulos importados. Conseguir executar a aplicação e conseguir importá-la sem efeitos indesejados são verificações diferentes.
- Execute
python -m expense_appe confira 14000. Depois execute o comando de importação acima e confira somenteimported. - Em
__main__.py, altere somente 8000 para 9000 e execute de novo com-m. A saída deve ser 15000; o comando de importação continua mostrando somenteimported. - Restaure 8000. Mantendo o código, tente
python expense_app/__main__.pya partir deproject. Observe o erro sobre importação relativa sem pacote pai conhecido e volte à execução com-m, que deve mostrar novamente 14000. - Se iniciar o terminal dentro de
expense_appe a execução com-m expense_appnão localizar o pacote, volte à pasta paiproject. Confirme o nome, a extensão e a posição dos três arquivos antes de alterar caminhos de importação ou instalar componentes.
A organização de pastas deste exercício não é ainda uma distribuição instalável ou uma publicação num repositório de pacotes. Distribuir uma aplicação exige metadados como pyproject.toml, construção dos artefatos e testes de instalação num ambiente separado. Se o nome da pasta do pacote mudar, atualize também o nome usado nos comandos e nas importações feitas por outros módulos.




