uma - working with libraries in python




O que é__init__.py para? (7)

O que é o __init__.py em um diretório de origem do Python?


Além de rotular um diretório como um pacote Python e definir __all__ , __init__.py permite que você defina qualquer variável no nível do pacote. Fazer isso geralmente é conveniente se um pacote definir algo que será importado com frequência, de maneira semelhante à API. Este padrão promove a aderência à filosofia Pythonic "flat is better than nested".

Um exemplo

Aqui está um exemplo de um dos meus projetos, no qual eu freqüentemente importo um sessionmaker chamado Session para interagir com meu banco de dados. Eu escrevi um pacote de "banco de dados" com alguns módulos:

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

Meu __init__.py conté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 a Session aqui, posso iniciar uma nova sessão usando a sintaxe abaixo. Este código seria o mesmo executado dentro ou fora do diretório do pacote "database".

from database import Session
session = Session()

É claro que essa é uma pequena conveniência - a alternativa seria definir Session em 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

Há um tópico reddit bastante interessante que cobre usos apropriados de __init__.py aqui:

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 arquivos __init__.py devem ser muito finos para evitar violar a filosofia "explícito é melhor do que implícito".


Arquivos chamados __init__.py são usados ​​para marcar diretórios no disco como diretórios de pacotes do Python. Se você tiver os arquivos

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

e mydir está no seu caminho, você pode importar o código em module.py como

import spam.module

ou

from spam import module

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

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

import spam

com base this


Em Python, a definição de pacote é muito simples. Como o Java, a estrutura hierárquica e a estrutura de diretórios são as mesmas. Mas você precisa ter o __init__.py em um pacote. Vou explicar o arquivo __init__.py 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__.py pode estar vazio, desde que exista. Indica que o diretório deve ser considerado como um pacote. É claro que o __init__.py também pode definir o conteúdo apropriado.

Se adicionarmos uma função em 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 

Então seguimos o pacote de hierarquia e chamamos module_n1 a função. Nós podemos usar __init__.py em subPackage_b desta forma:

__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 de módulos está sujeito ao conteúdo __init__.py .


Embora o Python funcione sem um arquivo __init__.py você ainda deve incluir um.

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

Há também um caso em que você pode realmente usar um arquivo __init__.py :

Imagine que você tivesse a seguinte estrutura de arquivos:

main_methods 
    |- methods.py

E o methods.py continha isto:

def foo():
    return 'foo'

Para usar o 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 o main_methods methods.py dentro de main_methods (tempos de execução / dependências, por exemplo), mas só quer importar main_methods .

Se você mudou o nome de methods.py para __init__.py então você poderia usar foo() importando apenas 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 o JSON , onde a execução do import json está realmente importando o __init__.py do pacote json ( veja a estrutura do arquivo do pacote aqui ):

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


Faz parte de um pacote Aqui está a documentação.

Os arquivos __init__.py são necessários para fazer com que o Python trate os diretórios como contendo pacotes; isso é feito para evitar que diretórios com um nome comum, como string , ocultem involuntariamente módulos válidos que ocorrem posteriormente (mais profundamente) no caminho de pesquisa do módulo. No caso mais simples, __init__.py pode ser apenas um arquivo vazio, mas também pode executar o código de inicialização do pacote ou definir a variável __all__ , descrita posteriormente.


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

root\
    stuff\
         other.py

    morestuff\
         another.py

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


__init__.py tratará o diretório no qual ele está como um módulo carregável.

Para as pessoas que preferem ler códigos, eu coloco 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
>>> 




module