Skip to main content

__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:

  1. Localiza diretório
  2. Executa __init__.py
  3. Cria objeto módulo do pacote
  4. 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__.py pode 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.