O que é o __init__.py?


Respostas:


1454

Costumava ser uma parte necessária de um pacote ( antigo "pacote regular" anterior à 3.3 , e não mais recente "pacote de namespace" 3.3+ mais recente ).

Aqui está a documentação.

Python define dois tipos de pacotes, pacotes regulares e pacotes de namespace. Pacotes regulares são pacotes tradicionais, como existiam no Python 3.2 e versões anteriores. Um pacote regular é normalmente implementado como um diretório que contém um __init__.pyarquivo. Quando um pacote regular é importado, esse __init__.pyarquivo é executado implicitamente e os objetos que ele define são vinculados aos nomes no espaço para nome do pacote. O __init__.pyarquivo pode conter o mesmo código Python que qualquer outro módulo pode conter, e o Python adicionará alguns atributos adicionais ao módulo quando ele for importado.

Mas basta clicar no link, ele contém um exemplo, mais informações e uma explicação dos pacotes de namespace, o tipo de pacote sem __init__.py.


187
O que isso significa: "isso é feito para impedir que diretórios com um nome comum, como string, ocultem acidentalmente módulos válidos que ocorrem posteriormente no caminho de pesquisa do módulo"?
Carl G

97
O @CarlG Python pesquisa uma lista de diretórios para resolver nomes, por exemplo, instruções de importação. Como esses podem ser qualquer diretório e os arbitrários podem ser adicionados pelo usuário final, os desenvolvedores precisam se preocupar com os diretórios que compartilham um nome com um módulo Python válido, como 'string' no exemplo de documentação. Para aliviar isso, ele ignora os diretórios que não contêm um arquivo chamado _ _ init _ _.py (sem espaços), mesmo que esteja em branco.
Two-Bit Alquimista

186
@CarlG Tente isso. Crie um diretório chamado 'datetime' e nele crie dois arquivos em branco, o arquivo init.py (com sublinhados) e datetime.py. Agora abra um intérprete, importe o sys e o problema sys.path.insert(0, '/path/to/datetime'), substituindo esse caminho pelo caminho para o diretório que você acabou de criar. Agora tente algo parecido from datetime import datetime;datetime.now(). Você deve obter um AttributeError (porque está importando seu arquivo em branco agora). Se você repetisse essas etapas sem criar o arquivo init em branco, isso não aconteceria. Isso é o que se pretende impedir.
Alquimista de dois bits

4
@ DarekNędza Você tem algo configurado incorretamente se não pode simplesmente abrir um intérprete Python e emitir from datetime import datetimesem erros. Isso é bom desde a versão 2.3!
Alquimista de dois bits 5/05

5
@Sang: Isso está incorreto: builtinslista funções e classes internas , não módulos internos (cf. docs.python.org/3/tutorial/modules.html#the-dir-function ). Se você deseja listar os módulos internos , faça import sys; print(sys.builtin_module_names)(cf. docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Maggyero 17/01/19

842

Os arquivos nomeados __init__.pysão usados ​​para marcar diretórios no disco como diretórios de pacotes Python. Se você tiver os arquivos

mydir/spam/__init__.py
mydir/spam/module.py

e mydirestá no seu caminho, você pode importar o código module.pycomo

import spam.module

ou

from spam import module

Se você remover o __init__.pyarquivo, o Python não procurará mais submódulos dentro desse diretório; portanto, as tentativas de importar o módulo falharão.

O __init__.pyarquivo geralmente está vazio, mas pode ser usado para exportar partes selecionadas do pacote com um nome mais conveniente, manter funções de conveniência etc. etc. Dado o exemplo acima, o conteúdo do módulo init pode ser acessado como

import spam

com base nisso


96
Atualização: o arquivo __init__.pyfoi necessário no Python 2.X e ainda é necessário no Python 2.7.12 (eu testei), mas não é mais necessário (supostamente) do Python 3.3 em diante e não é necessário no Python 3.4.3 (I testado). Consulte stackoverflow.com/questions/37139786 para obter mais detalhes.
Rob_before_edits

4
Não use. É um pacote "namespace", não um pacote regular. O pacote de namespace é usado para casos de uso muito raros. Você pode não precisar saber quando usá-lo. Basta usar __init__.py.
Metano #

2
no entanto, se você tiver setup.pye usar find_packages(), é necessário ter __init__.pyem todos os diretórios. Veja stackoverflow.com/a/56277323/7127824
techkuz

484

Além de rotular um diretório como um pacote Python e definir __all__, __init__.pypermite definir qualquer variável no nível do pacote. Isso geralmente é conveniente se um pacote definir algo que será importado com frequência, de maneira semelhante à API. Esse padrão promove a aderência à filosofia "plana é melhor do que aninhada".

Um exemplo

Aqui está um exemplo de um dos meus projetos, no qual eu frequentemente importo uma sessionmakerchamada Sessionpara interagir com meu banco de dados. Eu escrevi um pacote "database" com alguns módulos:

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

My __init__.pycontém o seguinte código:

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Como defino Sessionaqui, posso iniciar uma nova sessão usando a sintaxe abaixo. Esse código seria o mesmo executado dentro ou fora do diretório do pacote "database".

from database import Session
session = Session()

Obviamente, essa é uma pequena conveniência - a alternativa seria definir Sessionem um novo arquivo como "create_session.py" no meu pacote de banco de dados e iniciar novas sessões usando:

from database.create_session import Session
session = Session()

Leitura adicional

Existe um tópico reddit bastante interessante que cobre os usos apropriados __init__.pyaqui:

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

A opinião da maioria parece ser que os __init__.pyarquivos devem ser muito finos para evitar violar a filosofia "explícito é melhor que implícito".


3
engine, sessionmaker, create_engine, E ospodem também ser importados de databaseagora ... parece que você fez uma confusão de que namespace.
ArtOfWarfare 23/09

9
@ArtOfWarfare, você pode usar __all__ = [...]para limitar o que é importado import *. Além disso, sim, você fica com um namespace de nível superior confuso.
Nathan Gould

Posso saber o que é o 'DATABASE URL'? Tentei replicar isso encerrando o create_engine com 'mysql + mysqldb: // root: python @ localhost: 3306 / test', mas ele não funciona. Obrigado.
SunnyBoiz

2
Como você acessaria a classe 'Session' definida no init de dentro do pacote, por exemplo, quieries.py?
precisa saber é o seguinte

253

Existem 2 razões principais para __init__.py

  1. Por conveniência: os outros usuários não precisarão conhecer a localização exata de suas funções na hierarquia de pacotes.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    # in file1.py
    def add():
        pass

    outras pessoas podem chamar add () por

    from your_package import add

    sem saber file1, como

    from your_package.file1 import add
  2. Se você deseja que algo seja inicializado; por exemplo, log (que deve ser colocado no nível superior):

    import logging.config
    logging.config.dictConfig(Your_logging_config)

7
ah, antes de ler sua resposta, pensei que chamar uma função explicitamente a partir de sua localização é uma boa prática.
Aerin 26/02

2
@Aerin, seria melhor não considerar declarações curtas (ou, nesse caso, conclusões subjetivas) sempre verdadeiras. A importação de __init__.pypode ser útil algumas vezes, mas nem sempre.
Tobias Sette

2
Esses códigos são executados no momento da importação ou no tempo de execução?
user1559897 27/01

111

O __init__.pyarquivo faz o Python tratar os diretórios que o contêm como módulos.

Além disso, este é o primeiro arquivo a ser carregado em um módulo, portanto, você pode usá-lo para executar o código que deseja executar cada vez que um módulo é carregado ou especificar os submódulos a serem exportados.


89

Desde o Python 3.3, __init__.py não é mais necessário definir diretórios como pacotes Python importáveis.

Verifique PEP 420: Pacotes implícitos de espaço para nome :

Suporte nativo para diretórios de pacotes que não exigem __init__.pyarquivos de marcadores e podem se estender automaticamente a vários segmentos de caminho (inspirados em várias abordagens de terceiros para pacotes de namespace, conforme descrito no PEP 420 )

Aqui está o teste:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

referências:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__. py não é necessário para pacotes em Python 3?


3
É um pacote "namespace". Não o use para pacotes regulares.
Metano #

@methan, você poderia elaborar seu comentário?
Robert Lugg


57

No Python, a definição de pacote é muito simples. Como Java, a estrutura hierárquica e a estrutura de diretórios são as mesmas. Mas você tem que ter __init__.pyem um pacote. Vou explicar o __init__.pyarquivo com o exemplo abaixo:

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.pypode estar vazio, enquanto existir. Indica que o diretório deve ser considerado como um pacote. Claro, __init__.pytambém pode definir o conteúdo apropriado.

Se adicionarmos uma função no module_n1:

def function_X():
    print "function_X in module_n1"
    return

Depois de correr:

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

Em seguida, seguimos o pacote de hierarquia e chamamos module_n1 a função. Podemos usar __init__.pyno subPackage_b assim:

__all__ = ['module_n2', 'module_n3']

Depois de correr:

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

Portanto, usando a importação *, o pacote do módulo está sujeito ao __init__.pyconteúdo.


Como meu setup.py procurará fazer a mesma importação através da biblioteca empacotada? from package_x.subPackage_b.module_n1 import function_X
technazi 4/09/19

então a chave aqui é "usando * a importação, o pacote do módulo está sujeito ao conteúdo init .py"
Minnie em

54

Embora o Python funcione sem um __init__.pyarquivo, você ainda deve incluir um.

Ele especifica que um pacote deve ser tratado como um módulo; portanto, inclua-o (mesmo que esteja vazio).

Também existe um caso em que você pode realmente usar um __init__.pyarquivo:

Imagine que você tivesse a seguinte estrutura de arquivos:

main_methods 
    |- methods.py

E methods.pycontinha isso:

def foo():
    return 'foo'

Para usar, foo()você precisaria de um dos seguintes:

from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()

Talvez você precise (ou queira) manter methods.pydentro main_methods(tempos de execução / dependências, por exemplo), mas você só deseja importar main_methods.


Se você mudou o nome de methods.pypara, __init__.pyentão você pode usarfoo() apenas importando main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'

Isso funciona porque __init__.py é tratado como parte do pacote.


Alguns pacotes Python realmente fazem isso. Um exemplo é com JSON , em que a execução import jsoné realmente importada __init__.pydo jsonpacote ( consulte a estrutura do arquivo do pacote aqui ):

Código fonte: Lib/json/__init__.py


39

__init__.py tratará o diretório em que está como um módulo carregável.

Para quem prefere ler código, coloquei o comentário do Alquimista de dois bits aqui.

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 

30

Facilita a importação de outros arquivos python. Quando você colocou esse arquivo em um diretório (digamos, stuff) contendo outros arquivos py, você pode fazer algo como importar coisas.outros.

root\
    stuff\
         other.py

    morestuff\
         another.py

Sem isso __init__.pydentro do diretório, você não poderia importar other.py, porque o Python não sabe onde está o código-fonte e não consegue reconhecê-lo como um pacote.


2
Eu tenho a mesma estrutura no meu projeto (python 3.4), mas não consigo fazer com que another.py veja other.py. Como devo fazer a importação? de root.stuff importar outro? Ele funciona no modo de depuração VSCode, mas não na linha de comando. Alguma ideia?
Rodrigorf 23/10

10

Um __init__.pyarquivo facilita as importações. Quando um __init__.pyestá presente em um pacote, a função a()pode ser importada do arquivo da seguinte b.pymaneira:

from b import a

Sem ele, no entanto, você não pode importar diretamente. Você precisa alterar o caminho do sistema:

import sys
sys.path.insert(0, 'path/to/b.py')

from b import a

o que você quer dizer com "a função a () pode ser importada do arquivo b.py [snippet] Sem ela, no entanto, você não pode importar diretamente. "? Posso importar a função a () do arquivo b.py sem __init__.py.
aderchox
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.