__init__ nos imports | Python
__init__nos imports | Python
O que é __init__.py
__init__.py é um arquivo especial que:
- Define um diretório como pacote Python
- É executado quando o pacote é importado
- Pode controlar o namespace público do pacote
- Pode expor uma API simplificada
- Pode executar inicialização controlada
Quando ele é executado
Sempre que o pacote for importado:
import app
ou
from app import algo
O Python executa:
app/__init__.py
Uma única vez por processo.
Exemplo 1 — __init__ vazio
Estrutura:
app/
├── __init__.py
├── models.py
└── services.py
Arquivo:
# app/__init__.py
Função:
- Apenas marca o diretório como pacote
- Não altera comportamento
Uso:
import app
Exemplo 2 — Reexportando símbolos
Estrutura:
app/
├── __init__.py
├── models.py
models.py:
class Book:
pass
init.py:
from .models import Book
__all__ = ["Book"]
Agora é possível:
from app import Book
Sem precisar:
from app.models import Book
Exemplo 3 — Criando uma API pública limpa
Estrutura maior:
project/
│
└── app/
├── __init__.py
├── database.py
├── models.py
└── services.py
init.py:
from .models import Book
from .services import BookService
__all__ = [
"Book",
"BookService"
]
Uso externo:
from app import Book, BookService
Sem expor estrutura interna.
Exemplo 4 — Código executado na importação
# app/__init__.py
print("Pacote carregado")
Quando fizer:
import app
Saída:
Pacote carregado
Importante:
- Executado apenas uma vez
- Evite lógica pesada
- Pode ser usado para registro de plugins
Exemplo 5 — Inicialização de logging
# app/__init__.py
import logging
logging.basicConfig(level=logging.INFO)
Agora qualquer módulo que importar app terá logging configurado.
Exemplo 6 — Lazy loading (import sob demanda)
# app/__init__.py
def get_database():
from .database import Database
return Database()
A importação ocorre apenas quando a função for chamada.
Exemplo 7 — Encadeamento de subpacotes
Estrutura:
project/
│
└── app/
├── __init__.py
├── models/
│ ├── __init__.py
│ └── book.py
└── services/
├── __init__.py
└── book_service.py
models/init.py:
from .book import Book
__all__ = ["Book"]
services/init.py:
from .book_service import BookService
__all__ = ["BookService"]
app/init.py:
from .models import Book
from .services import BookService
__all__ = ["Book", "BookService"]
Uso final:
from app import Book, BookService
Hierarquia organizada e controlada.
Exemplo 8 — Protegendo namespace
Sem __all__:
from .models import *
Todos símbolos públicos serão exportados.
Com __all__:
__all__ = ["Book"]
Somente Book será exportado ao usar:
from app import *
Exemplo 9 — Evitando imports circulares
Você pode mover dependências para dentro do __init__ para reorganizar dependências.
Exemplo:
# app/__init__.py
from .models import Book
Evita importar módulos diretamente entre si.
O que NÃO fazer no __init__
- Não colocar lógica pesada
- Não abrir conexões de banco automaticamente
- Não executar código que cause side-effects inesperados
- Não manipular sys.path
Como o Python trata __init__
Internamente:
- Localiza diretório
- Executa
__init__.py - Cria objeto módulo do pacote
- Armazena em
sys.modules
O pacote vira um namespace executável.
Diferença entre pasta com e sem __init__
Sem __init__.py (Python 3.3+):
- Torna-se namespace package
- Funciona, mas menos explícito
- Pode gerar ambiguidade
Com __init__.py:
- Controle total
- Melhor compatibilidade
- Mais previsível
Boa prática profissional: sempre incluir.
Padrão profissional recomendado
project/
│
└── package_name/
├── __init__.py
├── domain/
├── services/
└── infrastructure/
init.py deve:
- Expor apenas interface pública
- Manter encapsulamento
- Evitar lógica de execução
Resumo técnico
__init__.py:
- Marca diretório como pacote
- Executa código ao importar
- Controla exportações com
__all__ - Define API pública
- Organiza namespace
É um mecanismo de controle arquitetural, não apenas um arquivo obrigatório.
Outros detalhes:
-
O conteúdo de
__init__.pypode estar vazio. Mesmo assim, ele ainda indica que o diretório é um pacote. -
Você pode também usá-lo para inicializações de pacote, como:
- Importar submódulos automaticamente
- Configurar variáveis globais
- Rodar código ao importar o pacote
Curiosidade
A partir do Python 3.3, o __init__.py não é mais estritamente necessário para o reconhecimento de pacotes. Mas ainda é uma boa prática incluí-lo, especialmente em projetos estruturados ou quando se quer manter compatibilidade com versões anteriores.