✅ Artigo atualizado em Setembro 2026 Corrigimos a explicação sobre pacotes sem
__init__.py(namespace packages, PEP 420) e sobre o__all__, completamos o exemplo que faltava e adicionamos resposta rápida, a diferença para o método__init__das classes, tabela módulo vs pacote, erros comuns com traceback e 8 exercícios resolvidos. Saídas conferidas no Python 3.10 e 3.13.
Resposta rápida
O __init__.py é o arquivo que transforma uma pasta em pacote regular do Python. Ele roda automaticamente na primeira importação do pacote e serve para inicializá-lo, expor nomes (from .modulo import funcao) e definir __all__. Pode ficar vazio. Não confunda com o método __init__ das classes.
1
2
3
4
5
6
7
# loja/__init__.py
print("Inicializando o pacote loja")
from .precos import com_desconto # loja/precos.py define com_desconto()
# main.py (fora da pasta loja)
import loja # Inicializando o pacote loja
print(loja.com_desconto(100)) # 90.0
Resumo em 30 segundos:
- O arquivo
__init__.pymarca uma pasta como pacote; o método__init__inicializa objetos de uma classe. Nomes iguais, papéis diferentes. - Ele é executado uma vez por processo, na primeira importação (inclusive ao importar só um submódulo, como
from loja.precos import com_desconto). - Um
__init__.pyvazio já basta para ter um pacote regular. - Sem ele, desde o Python 3.3 a pasta vira namespace package (PEP 420): importa, mas sem código de inicialização.
- O
__all__só afeta ofrom pacote import *; não torna nada privado.
Salve salve Pythonista!
Neste artigo, vamos entender pra que serve o arquivo __init__.py, quando ele é executado, o que colocar dentro dele e como resolver os erros de importação mais comuns em projetos com pacotes.
Se você chegou aqui procurando o def __init__(self) das classes, pule para a seção que explica a diferença entre os dois: o nome é parecido, mas o assunto é outro.
Então vamos nessa!
Vá Direto ao Assunto…
- O que é o
__init__.py? __init__.pyvs método__init__de uma classe- Formas de uso do
__init__.py - Exemplo Completo
- Quando Usar all
- Namespace Packages (Python 3.3+)
- Módulo, pacote regular e namespace package: qual a diferença?
- Erros comuns
- Exercícios resolvidos
O que é o __init__.py?
O arquivo __init__.py é uma maneira de indicar ao Python que o diretório no qual ele se encontra deve ser tratado como um pacote regular (regular package).
No Python, um pacote é uma forma de estruturar os módulos (arquivos .py) de uma forma hierárquica.
Quando um pacote regular é importado, o seu __init__.py é executado automaticamente, e tudo o que ele define passa a fazer parte do namespace do pacote. A documentação oficial descreve esse comportamento na seção de pacotes do tutorial do Python e, em detalhes, na referência do sistema de importação (regular packages).
E sem o __init__.py? Desde o Python 3.3 (PEP 420), um diretório sem esse arquivo ainda pode ser importado, mas como um namespace package: um tipo especial de pacote que não executa código de inicialização, não tem __all__ e pode ser formado por “pedaços” espalhados em vários diretórios. Falamos mais sobre isso na seção Namespace Packages.
Na prática, para organizar o código do seu próprio projeto, o __init__.py continua sendo o caminho recomendado: ele deixa explícito que aquele diretório é um pacote e evita surpresas com ferramentas que só procuram pacotes regulares (como o find_packages() do setuptools).
Veja um exemplo:
1
2
3
4
5
6
7
# Estrutura de um projeto exemplo
meu_projeto/
__init__.py
modulo1.py
subpacote/
__init__.py
modulo2.py
__init__.py vs método __init__ de uma classe
Muita gente busca “__init__ python” querendo uma coisa e encontra a outra. São dois assuntos diferentes que só dividem o nome (os dois sublinhados de cada lado são a convenção do Python para nomes especiais, os famosos dunders):
- O arquivo
__init__.pyfica dentro de uma pasta e é executado quando o pacote é importado. - O método
__init__fica dentro de umaclasse é executado a cada objeto criado. Ele é o inicializador (o “construtor”, no vocabulário de outras linguagens) e preenche os atributos emself. Explicamos esse método em detalhes no post sobre classes e objetos em Python, na seção do construtor.
Veja os dois no mesmo projeto, e a ordem em que cada um roda:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# loja/__init__.py (ARQUIVO do pacote)
print("1) Rodando loja/__init__.py (arquivo do pacote)")
# loja/produto.py
class Produto:
def __init__(self, nome, preco): # MÉTODO __init__ (inicializador da classe)
print(f"2) Rodando Produto.__init__ para {nome}")
self.nome = nome
self.preco = preco
# main.py (fora da pasta loja)
from loja.produto import Produto # executa loja/__init__.py
caneta = Produto("Caneta", 2.5) # executa Produto.__init__
print(caneta.nome, caneta.preco)
Saída ao rodar python main.py:
1
2
3
1) Rodando loja/__init__.py (arquivo do pacote)
2) Rodando Produto.__init__ para Caneta
Caneta 2.5
Arquivo __init__.py
|
Método __init__
|
|
|---|---|---|
| Onde fica | Dentro de uma pasta (pacote) | Dentro de uma class
|
| Quando roda | Na primeira importação do pacote | A cada objeto criado (Produto(...)) |
| Quantas vezes | Uma vez por processo | Uma vez por instância |
| Para que serve | Marcar a pasta como pacote, inicializar, expor nomes, __all__
|
Definir os atributos iniciais do objeto em self
|
| Recebe parâmetros? | Não | Sim: self e os argumentos passados na criação |
Formas de uso do __init__.py
Indicação de Pacotes
O uso mais simples do __init__.py é indicar ao Python que o diretório é um pacote.
Um __init__.py vazio já cumpre esse papel.
Por exemplo: supondo um diretório meu_projeto com estrutura mencionada acima, mesmo um __init__.py vazio permitirá importações.
Imagine que modulo1.py define a função ola() e subpacote/modulo2.py define a função tchau():
1
2
3
4
5
6
7
# meu_projeto/modulo1.py
def ola():
return "Olá do modulo1!"
# meu_projeto/subpacote/modulo2.py
def tchau():
return "Tchau do modulo2!"
Com os dois __init__.py vazios, um script que está no diretório acima de meu_projeto já consegue importar os módulos:
1
2
3
4
5
import meu_projeto.modulo1
from meu_projeto.subpacote import modulo2
print(meu_projeto.modulo1.ola())
print(modulo2.tchau())
E a saída será:
1
2
Olá do modulo1!
Tchau do modulo2!
Inicialização de Pacote
O __init__.py pode ser utilizado para realizar inicializações de pacotes. Isso é útil para configurar variáveis de ambiente, registros ou outras rotinas de inicialização:
1
2
3
4
5
6
# meu_projeto/__init__.py
print("Pacote 'meu_projeto' inicializado.")
CONFIG = {
'versao': '1.0',
'autor': 'Seu Nome'
}
Dessa forma, você pode importar a variável CONFIG com from meu_projeto import CONFIG e utilizar em qualquer lugar do seu código.
Definindo Exportações
Através do __init__.py, podemos definir quais nomes serão importados quando alguém usar from pacote import *.
Usamos a variável especial __all__ para indicar esses nomes/módulos:
1
2
# meu_projeto/__init__.py
__all__ = ['modulo1']
Com isso, o from meu_projeto import * passa a trazer apenas modulo1:
1
2
3
4
5
6
from meu_projeto import *
print(modulo1.ola())
print('subpacote' in dir())
from meu_projeto.subpacote import modulo2 # continua funcionando
print(modulo2.tchau())
E a saída será:
1
2
3
Olá do modulo1!
False
Tchau do modulo2!
Atenção: o __all__ só afeta o import *. Ele não esconde nada: importações explícitas, como import meu_projeto.subpacote ou from meu_projeto.subpacote import modulo2, continuam funcionando normalmente.
Importações Relativas
Dentro do __init__.py podemos usar importações relativas (com .) para trazer para o nível do pacote nomes definidos nos módulos internos. Assim, quem usa o pacote escreve from minha_aplicacao import funcao1 em vez de caminhos longos:
1
2
3
# minha_aplicacao/__init__.py
from .modulo1 import funcao1
from .subpacote.modulo2 import Classe2
Está curtindo esse conteúdo? ![]()
Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?
Exemplo Completo
Para demonstrar como o __init__.py é utilizado em um projeto, vamos criar uma estrutura de projeto mais completa.
Estrutura do Projeto
Essa será a estrutura do projeto que vamos utilizar para demonstrar o uso do arquivo __init__.py:
1
2
3
4
5
6
minha_aplicacao/
__init__.py
modulo1.py
subpacote/
__init__.py
modulo2.py
Implementação
- Arquivo
minha_aplicacao/__init__.py
1
2
3
4
5
6
print("Pacote 'minha_aplicacao' inicializado.")
from .modulo1 import saudacao
from .subpacote.modulo2 import ClasseDeExemplo
__all__ = ['saudacao', 'ClasseDeExemplo']
- Arquivo
minha_aplicacao/modulo1.py
1
2
def saudacao():
return "Olá do módulo 1!"
- Arquivo
minha_aplicacao/subpacote/__init__.py
1
# Pode estar vazio ou ter importações/inicializações específicas
- Arquivo
minha_aplicacao/subpacote/modulo2.py
1
2
3
4
5
6
class ClasseDeExemplo:
def __init__(self):
self.mensagem = "Classe de exemplo do módulo 2 no subpacote."
def exibir_mensagem(self):
return self.mensagem
Criei o Ebookr.ai, uma plataforma que usa IA para gerar ebooks profissionais sobre qualquer tema - com capa gerada por IA, infográficos automáticos e exportação em PDF. Confere!
Utilização
Depois de criar a estrutura do nosso projeto, podemos importar e utilizar os módulos e classes conforme necessário:
1
2
3
4
5
6
# main.py (arquivo principal fora do pacote)
from minha_aplicacao import saudacao, ClasseDeExemplo
print(saudacao())
instancia = ClasseDeExemplo()
print(instancia.exibir_mensagem())
E a saída será (repare que a primeira linha vem do print do __init__.py, executado na importação):
1
2
3
Pacote 'minha_aplicacao' inicializado.
Olá do módulo 1!
Classe de exemplo do módulo 2 no subpacote.
Quando Usar all
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# __init__.py
__all__ = ['funcao_publica', 'ClassePublica']
def funcao_publica():
return "Pública"
def _funcao_privada():
return "Privada"
class ClassePublica:
pass
class _ClassePrivada:
pass
Quando alguém faz from pacote import *, apenas funcao_publica e ClassePublica serão importadas.
Isso não torna _funcao_privada inacessível: from pacote import _funcao_privada continua funcionando. O __all__ documenta a API pública e controla o import *, mas não é um mecanismo de privacidade.
Namespace Packages (Python 3.3+)
Desde Python 3.3 (PEP 420), um diretório sem __init__.py pode ser importado como namespace package. Ele funciona para importar módulos, mas é diferente de um pacote regular: não executa código de inicialização, não tem __file__ (vale None) e várias pastas com o mesmo nome em lugares diferentes do sys.path são combinadas num único pacote.
O uso pensado para namespace packages é dividir um mesmo pacote entre várias distribuições instaladas separadamente (por exemplo, plugins que compartilham o prefixo empresa.). Para o código do seu próprio projeto, prefira pacotes regulares. Resumindo:
✅ Use __init__.py quando:
- Precisa inicializar o pacote
- Quer controlar exports com
__all__ - Deseja imports simplificados
❌ Pode omitir quando:
- Quer, de fato, um namespace package (pacote dividido entre várias pastas ou distribuições)
- Entende que não terá inicialização nem
__all__naquele nível
Organizar um projeto em módulos e pacotes parece detalhe, mas é isso que separa código bagunçado de código profissional. Aprender essa organização na prática, com projetos guiados, é proposta da Jornada Python:
Módulo, pacote regular e namespace package: qual a diferença?
Um módulo é um único arquivo .py: tudo o que ele define (as funções, classes e variáveis) pode ser importado pelo nome do arquivo, sem a extensão. Um pacote é uma pasta que agrupa módulos e outros pacotes (subpacotes), acessados com ponto: loja.precos, loja.relatorios.vendas.
Na hora do import, o Python procura esses nomes nas pastas listadas em sys.path: a pasta do script que você executou, a biblioteca padrão e o site-packages, onde o pip instala as bibliotecas de terceiros (dentro do seu ambiente virtual, se você estiver usando um). Por isso o mesmo import loja pode funcionar num terminal e falhar em outro, como você vai ver em Erros comuns.
| Módulo | Pacote regular | Namespace package | |
|---|---|---|---|
| O que é | Um arquivo .py
|
Uma pasta com __init__.py
|
Uma pasta sem __init__.py (Python 3.3+) |
| Exemplo | precos.py |
loja/__init__.py + loja/precos.py
|
plugins/csv_plugin.py |
| Roda código ao importar? | Sim, o próprio arquivo | Sim, o __init__.py
|
Não |
Aceita __all__ no nível do pacote? |
Sim (no próprio arquivo) | Sim | Não |
__file__ |
Caminho do .py
|
Caminho do __init__.py
|
None |
| Pode estar espalhado em várias pastas? | Não | Não | Sim, pastas de mesmo nome no sys.path são combinadas |
| Quando usar | Código pequeno ou uma responsabilidade só | O padrão para organizar o código do seu projeto | Plugins ou distribuições separadas que compartilham um prefixo |
Erros comuns
Os exemplos abaixo usam esta estrutura (a pasta projeto/ é onde você abre o terminal):
1
2
3
4
5
6
7
projeto/
loja/
__init__.py
precos.py # def com_desconto(valor): return valor * 0.9
relatorio.py
scripts/
gerar.py
1. ModuleNotFoundError: No module named 'loja'
Você roda um script que está em outra pasta e ele tenta importar o pacote:
1
2
3
4
# scripts/gerar.py
from loja.precos import com_desconto
print(com_desconto(50))
1
2
3
4
5
$ python scripts/gerar.py
Traceback (most recent call last):
File "/home/voce/projeto/scripts/gerar.py", line 1, in <module>
from loja.precos import com_desconto
ModuleNotFoundError: No module named 'loja'
Ao rodar python scripts/gerar.py, o Python coloca em sys.path a pasta do script (scripts/), e não a pasta de onde você chamou o comando. Como loja/ não está dentro de scripts/, o import falha. O mesmo erro aparece no terminal interativo ou com python -m se você estiver em outra pasta, fora de projeto/.
Correção: transforme scripts/ em pacote (crie um scripts/__init__.py vazio) e execute como módulo a partir de projeto/, com python -m scripts.gerar. Assim a pasta atual entra no sys.path e a saída é 45.0. Em projetos maiores, a solução definitiva é instalar o seu pacote no ambiente virtual (pip install -e .).
2. ImportError: attempted relative import with no known parent package
O arquivo usa import relativo (com ponto) e você o executa diretamente como script:
1
2
3
4
# loja/relatorio.py
from .precos import com_desconto
print(com_desconto(200))
1
2
3
4
5
$ python loja/relatorio.py
Traceback (most recent call last):
File "/home/voce/projeto/loja/relatorio.py", line 1, in <module>
from .precos import com_desconto
ImportError: attempted relative import with no known parent package
Rodado assim, o arquivo vira o módulo __main__ e o Python não sabe que ele pertence ao pacote loja, então o . não aponta para lugar nenhum.
Correção: a partir de projeto/, rode python -m loja.relatorio (saída: 180.0). Com -m, o Python importa loja primeiro (executando o loja/__init__.py) e o import relativo passa a funcionar.
3. Import circular entre o __init__.py e um módulo do pacote
O __init__.py importa um módulo, e esse módulo importa de volta algo definido no __init__.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# loja/__init__.py
from .produtos import Produto
def formatar_preco(valor):
return f"R$ {valor:.2f}"
# loja/produtos.py
from loja import formatar_preco # loja ainda não terminou de carregar!
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def etiqueta(self):
return f"{self.nome}: {formatar_preco(self.preco)}"
Um simples import loja resulta em (Python 3.10 a 3.12):
1
ImportError: cannot import name 'formatar_preco' from partially initialized module 'loja' (most likely due to a circular import) (/home/voce/projeto/loja/__init__.py)
No Python 3.13 a mensagem muda para ImportError: cannot import name 'formatar_preco' from 'loja' (consider renaming '.../loja/__init__.py' if it has the same name as a library you intended to import), mas a causa é a mesma: quando produtos.py pede formatar_preco, o __init__.py ainda está parado na linha 1 e a função não existe.
Correção: mova o código compartilhado para um módulo próprio e deixe o __init__.py só reexportar:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# loja/formatacao.py
def formatar_preco(valor):
return f"R$ {valor:.2f}"
# loja/produtos.py
from .formatacao import formatar_preco
# ... classe Produto igual à de cima
# loja/__init__.py
from .formatacao import formatar_preco
from .produtos import Produto
# main.py
from loja import Produto
print(Produto("Caneta", 2.5).etiqueta()) # Caneta: R$ 2.50
4. Esquecer que o __init__.py roda em toda importação
Qualquer import que passe pelo pacote executa o __init__.py antes, inclusive from pacote.submodulo import funcao. Código pesado ali deixa tudo lento:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# relatorios/__init__.py
import time
print("Carregando relatórios... (3 segundos)")
time.sleep(3) # simula ler um arquivo grande ou abrir conexão com o banco
DADOS = [120, 80, 45]
# relatorios/util.py
def somar(valores):
return sum(valores)
# main.py
import time
inicio = time.perf_counter()
from relatorios.util import somar # só queria a função somar...
print(somar([1, 2, 3]))
print(f"Tempo: {time.perf_counter() - inicio:.1f}s")
1
2
3
Carregando relatórios... (3 segundos)
6
Tempo: 3.0s
Correção: deixe o __init__.py leve (imports, __all__, __version__) e coloque o trabalho pesado numa função chamada só quando for preciso:
1
2
3
4
5
6
7
8
9
10
11
12
# relatorios/__init__.py
import time
_dados = None
def carregar_dados():
global _dados
if _dados is None:
print("Carregando relatórios... (3 segundos)")
time.sleep(3)
_dados = [120, 80, 45]
return _dados
Com essa versão, o mesmo main.py imprime 6 e Tempo: 0.0s: os dados só são carregados quando alguém chama carregar_dados().
Exercícios resolvidos
Crie uma pasta vazia para os exercícios e rode cada main.py a partir dela. Em todos, os arquivos main.py ficam fora da pasta do pacote.
Exercício 1. Crie um pacote calc com um módulo operacoes.py que define somar(a, b). Em main.py, importe a função e imprima somar(2, 3).
Ver solução
1
2
3
4
5
6
7
8
9
10
# calc/__init__.py -> arquivo vazio
# calc/operacoes.py
def somar(a, b):
return a + b
# main.py
from calc.operacoes import somar
print(somar(2, 3))
Saída: 5
O __init__.py vazio já faz de calc um pacote regular, e o submódulo é acessado com ponto: calc.operacoes.
Exercício 2. Adicione ao pacote calc um módulo extras.py com dobro(x). Altere o calc/__init__.py para que from calc import somar, dobro funcione, sem citar os submódulos no main.py.
Ver solução
1
2
3
4
5
6
7
8
9
10
11
12
# calc/extras.py
def dobro(x):
return x * 2
# calc/__init__.py
from .operacoes import somar
from .extras import dobro
# main.py
from calc import somar, dobro
print(somar(2, 3), dobro(10))
Saída: 5 20
Os imports relativos no __init__.py trazem as funções para o nível do pacote. É o mesmo truque que bibliotecas como o requests usam para você escrever requests.get em vez do caminho completo do módulo.
Exercício 3. (Estilo prova) Qual é a função do arquivo __init__.py em um diretório Python?
a) Definir o construtor das classes que estão no diretório.
b) Indicar que o diretório é um pacote regular e executar o código de inicialização dele na importação.
c) Permitir qualquer importação: sem ele, o Python 3 não importa a pasta de jeito nenhum.
d) Tornar privados todos os nomes que não estiverem no __all__.
Ver solução
Resposta: b.
A alternativa a descreve o método __init__ de uma classe. A c era verdade no Python 2, mas desde o Python 3.3 uma pasta sem __init__.py é importada como namespace package. A d está errada porque o __all__ só afeta o from pacote import *: from pacote import nome continua funcionando para qualquer nome.
Exercício 4. O pacote saudacoes tem só um __init__.py com print("Olá do __init__.py!"). Quantas vezes a mensagem aparece ao rodar o main.py abaixo?
1
2
3
4
import saudacoes
import saudacoes
from saudacoes import *
print("Fim")
Ver solução
1
2
Olá do __init__.py!
Fim
Só uma vez. Depois da primeira importação, o módulo fica guardado em sys.modules (você pode conferir com 'saudacoes' in sys.modules, que dá True) e as importações seguintes reutilizam o objeto já carregado, sem rodar o __init__.py de novo.
Exercício 5. (Estilo prova) Considere o pacote utilidades:
1
2
3
4
5
6
7
8
# utilidades/__init__.py
__all__ = ["limpar"]
def limpar(texto):
return texto.strip().lower()
def contar(texto):
return len(texto.split())
O que acontece ao executar o código abaixo?
1
2
3
4
from utilidades import *
print(limpar(" Olá Mundo "))
print(contar("olá mundo"))
a) Imprime olá mundo e 2.
b) Imprime olá mundo e depois dá NameError.
c) Dá ImportError já na primeira linha, porque contar não está no __all__.
d) Dá AttributeError, porque contar é privada.
Ver solução
Resposta: b.
1
2
3
4
5
olá mundo
Traceback (most recent call last):
File "/home/voce/exercicios/main.py", line 4, in <module>
print(contar("olá mundo"))
NameError: name 'contar' is not defined
O import * só traz o que está em __all__, então contar não entra no namespace do main.py. Mas ela não é privada: from utilidades import contar funciona e contar("olá mundo") retorna 2.
Exercício 6. Com a estrutura abaixo, com os dois __init__.py vazios, por que o main.py falha? Corrija sem mexer no pacote.
1
2
3
4
5
6
7
8
9
10
# app/__init__.py -> vazio
# app/banco/__init__.py -> vazio
# app/banco/conexao.py
def conectar():
return "conectado"
# main.py
import app
print(app.banco.conexao.conectar())
Ver solução
O erro é AttributeError: module 'app' has no attribute 'banco'. Importar um pacote não importa os subpacotes e submódulos automaticamente: o app/__init__.py está vazio, então app.banco nunca foi carregado. A correção é importar o caminho completo:
1
2
3
import app.banco.conexao
print(app.banco.conexao.conectar())
Saída: conectado
Outra opção seria o app/__init__.py importar o subpacote (from . import banco, e o banco/__init__.py fazer from . import conexao), mas o enunciado pedia para não mexer no pacote.
Exercício 7. Faça o pacote meupacote expor a versão "1.2.0" de forma que meupacote.__version__ funcione. Imprima também o nome do pacote.
Ver solução
1
2
3
4
5
6
7
8
# meupacote/__init__.py
__version__ = "1.2.0"
# main.py
import meupacote
print(meupacote.__version__)
print(meupacote.__name__)
1
2
1.2.0
meupacote
Tudo o que o __init__.py define vira atributo do pacote. Guardar __version__ ali é uma convenção antiga e muito comum em bibliotecas.
Exercício 8. Crie uma pasta plugins sem __init__.py, com um arquivo csv_plugin.py contendo NOME = "exportar_csv". O import funciona? O que plugins.__file__ mostra?
Ver solução
1
2
3
4
5
import plugins
import plugins.csv_plugin
print(plugins.__file__)
print(plugins.csv_plugin.NOME)
1
2
None
exportar_csv
Funciona, porque desde o Python 3.3 a pasta é importada como namespace package. O __file__ vale None porque não existe um __init__.py para apontar, e também não há código de inicialização nem __all__ no nível de plugins.
Quer praticar pacotes, módulos e imports montando projetos de verdade, com suporte de professor? Esse é o tipo de coisa que trabalhamos no nosso curso de Python completo, a Jornada Python.
Conclusão
Neste artigo, exploramos a funcionalidade e a importância do arquivo __init__.py em projetos Python.
Vimos que ele desempenha um papel crucial na indicação de pacotes, inicialização de pacotes e definição de exportações.
Além disso, através de exemplos práticos, mostramos como ele é utilizado na estruturação de projetos Python, tornando o código mais organizado e fácil de manter.
Para ver pacotes em ação num projeto real, confira o guia completo de Django: cada app criado com startapp é um pacote com seu próprio __init__.py. E para organizar imports e nomes de módulos, vale revisar o guia de estilos PEP 8.
Esperamos que este artigo tenha esclarecido quaisquer dúvidas sobre o __init__.py e motivado você a aplicá-lo corretamente em seus próprios projetos.
Valeu e até a próxima!
Perguntas frequentes
Pra que serve o __init__.py em Python?
O arquivo __init__.py transforma uma pasta em um pacote regular do Python. Ele é executado automaticamente na primeira vez que o pacote é importado e serve para inicializar o pacote, expor nomes dos módulos internos (por exemplo from .precos import com_desconto, permitindo from loja import com_desconto) e definir __all__. Um __init__.py vazio já basta para marcar a pasta como pacote.
O __init__.py é obrigatório no Python 3?
Não é obrigatório para importar. Desde o Python 3.3 (PEP 420), uma pasta sem __init__.py é importada como namespace package. Mas esse tipo de pacote não roda código de inicialização, não tem __all__ e __file__ vale None, e algumas ferramentas, como o find_packages() do setuptools, só encontram pacotes regulares. Para o código do seu próprio projeto, continue criando o __init__.py.
Qual a diferença entre o arquivo __init__.py e o método __init__ de uma classe?
São coisas diferentes que só compartilham o nome. O arquivo __init__.py fica dentro de uma pasta e é executado quando o pacote é importado. O método __init__, escrito como def __init__(self, ...) dentro de uma class, é o inicializador do objeto e roda a cada instância criada, por exemplo em Produto('Caneta', 2.5), para preencher atributos como self.nome.
O que colocar dentro do __init__.py?
Pode ficar vazio. Quando tiver conteúdo, o mais comum é: importar para o nível do pacote os nomes principais dos módulos internos (from .modulo import funcao), definir __all__ para controlar o from pacote import *, guardar metadados como __version__ = '1.0.0' e fazer inicializações leves. Evite código pesado (conexão com banco, leitura de arquivos grandes), porque ele roda em toda importação do pacote, inclusive de submódulos.
Quando o __init__.py é executado?
Na primeira vez que o pacote é importado no processo, seja com import pacote, from pacote import algo ou mesmo from pacote.submodulo import funcao. Depois disso o módulo fica guardado em sys.modules e novas importações reutilizam o que já foi carregado, sem executar o arquivo de novo.
Qual a diferença entre módulo e pacote em Python?
Um módulo é um único arquivo .py com funções, classes e variáveis, importado pelo nome do arquivo sem a extensão (import precos para precos.py). Um pacote é uma pasta que agrupa módulos e subpacotes; se tiver __init__.py é um pacote regular, se não tiver é um namespace package. Os submódulos são acessados com ponto, como em import loja.precos.
Como resolver ImportError: attempted relative import with no known parent package?
Esse erro aparece quando você roda como script um arquivo que usa import relativo, por exemplo python loja/relatorio.py com from .precos import com_desconto dentro. Rodado assim, o arquivo vira __main__ e perde a informação de que pertence ao pacote loja. A solução é executar a partir da pasta acima do pacote com python -m loja.relatorio, ou importar o módulo a partir de um script externo.
Em Python, qual é a função do arquivo __init__.py em um diretório?
Resposta de prova: indicar que o diretório é um pacote regular e executar o código de inicialização desse pacote quando ele é importado. Alternativas que costumam aparecer e estão erradas: ‘é o construtor das classes do diretório’ (isso é o método __init__), ‘é obrigatório para qualquer importação no Python 3’ (namespace packages dispensam o arquivo) e ‘torna privados os nomes fora do __all__’ (o __all__ só afeta o import *).
"Porque o Senhor dá a sabedoria, e da sua boca vem a inteligência e o entendimento" Pv 2:6