Módulos, Imports e Pacotes
Python organiza o código em módulos (arquivos) e pacotes (diretórios). O sistema de importação carrega o código uma vez por processo, o armazena em cache em sys.modules e expõe os nomes através do namespace de importação.
Receita
# myapp/services/users.py
from myapp.models.user import User
from myapp.utils.text import slugify
def list_active() -> list[User]:
return [u for u in User.all() if u.active]Quando usar isso:
- Dividir um script em crescimento em pacotes gerenciáveis
- Publicar bibliotecas reutilizáveis no PyPI
- Executar pontos de entrada de CLI via
python -m - Carregar preguiçosamente dependências opcionais pesadas
Exemplo de Trabalho
# myapp/__init__.py
__version__ = "1.0.0"
# myapp/config.py
from dataclasses import dataclass
import os
@dataclass(frozen=True)
class Settings:
debug: bool
database_url: str
def load_settings() -> Settings:
return Settings(
debug=os.getenv("DEBUG", "0") == "1",
database_url=os.getenv("DATABASE_URL", "sqlite:///local.db"),
)
# myapp/main.py
from myapp.config import load_settings
def main() -> None:
settings = load_settings()
print(f"debug={settings.debug} db={settings.database_url}")
if __name__ == "__main__":
main()Execute com: python -m myapp.main do diretório pai no PYTHONPATH.
O que isso demonstra:
- O
__init__.pydo pacote pode expor metadados de versão - Imports absolutos (
from myapp.config import ...) permanecem claros quando o pacote cresce - Guarda de entrada
if __name__ == "__main__"para módulos executáveis - O switch
-mdefine__package__corretamente para imports relativos dentro do pacote
Mergulho Profundo
Como Funciona
- Caminho de busca de importação -
sys.pathlista diretórios;PYTHONPATHe ossite-packagesdo venv o estendem. - Cache de módulo - A primeira importação executa o corpo do módulo; importações posteriores reutilizam
sys.modules. - Imports relativos -
from .config import load_settingsexigem contexto de pacote (-mou importação de pacote). - Pacotes de namespace - PEP 420 diretórios sem
__init__.pypodem participar de um namespace dividido. __all__- Documenta nomes públicos parafrom module import *(raro em código de aplicação).
Recomendação de Layout
project/
src/
myapp/
__init__.py
main.py
config.py
pyproject.toml
Instale em modo editável (uv pip install -e .) para que import myapp seja resolvido durante o desenvolvimento.
Notas Python
import importlib
def lazy_import(module: str):
return importlib.import_module(module)
# O bloco TYPE_CHECKING evita importação circular em tempo de execução
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from myapp.models import UserArmadilhas
- Importações circulares -
aimportabenquantobimportaa. Correção: Mova tipos compartilhados para um terceiro módulo ou use importação preguiçosa dentro de funções. - Executando arquivo diretamente -
python myapp/main.pyquebra imports relativos. Correção:python -m myapp.main. - Sobrescrita da biblioteca padrão - Nomear um arquivo
json.pyquebraimport json. Correção: Evite nomes da biblioteca padrão para módulos. - Efeitos colaterais na importação - Conexões de banco de dados no nível do módulo atrasam os testes. Correção: Funções de fábrica chamadas de
main. - Importações em estrela -
from utils import *polui o namespace. Correção: Importe símbolos explícitos.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Script de módulo único | <200 linhas, um autor | Múltiplos domínios emergindo |
Pacote com layout src | Bibliotecas e serviços | Notebook descartável |
importlib preguiçoso | Dependências opcionais pesadas (torch) | Dependência principal sempre necessária |
Pontos de entrada pluggy | Arquiteturas de plugin | Pacote interno simples |
FAQs
Qual a diferença entre import e from import?
import module vincula o objeto módulo. from module import name vincula o nome diretamente no namespace atual.
Preciso de __init__.py?
Pacotes regulares sim (ou pacote de namespace implícito sem ele). Um __init__.py vazio serve para marcar um pacote.
Como python -m ajuda?
Executa um módulo como __main__ com metadados de pacote corretos para que imports relativos funcionem.
O que é sys.path[0]?
O diretório que contém o script ou o diretório atual para -m. Instalações editáveis adicionam src ao path via metadados.
Como corrijo ImportError após refatoração?
Verifique o pacote no PYTHONPATH, use imports absolutos, verifique a descoberta de pacotes em pyproject.toml, reinstale em modo editável.
Posso importar do diretório pai?
Possível com hacks de path - desencorajado. Instale o pacote em modo editável ou configure um layout adequado em vez disso.
O que faz if TYPE_CHECKING?
Importa apenas para verificadores de tipo - evita importação circular em tempo de execução enquanto mantém as dicas.
Como funcionam os imports relativos?
Um ponto é o pacote atual; dois pontos é o pai. Requer contexto de pacote - não em scripts de nível superior.
Quando import * é aceitável?
Raramente - às vezes em __init__.py para reexportar APIs com __all__ explícito. Nunca em módulos de aplicação.
Como os pacotes de namespace diferem?
Múltiplos diretórios contribuem para um nome de pacote sem um único __init__.py - usado para ecossistemas de plugins.
Relacionados
- Guia Rápido de Ambientes Virtuais - dependências isoladas
- Layout
src- layout de pacote de produção - pyproject.toml explicado - metadados do pacote
- Arquivos e I/O - leitura de arquivos de configuração
Versões da Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.