__Init__.py não é necessário para pacotes no Python 3.3 ou superior


193

Estou usando o Python 3.5.1. Li o documento e a seção do pacote aqui: https://docs.python.org/3/tutorial/modules.html#packages

Agora, tenho a seguinte estrutura:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

Agora, enquanto estiver em /home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

Da mesma forma, agora em casa, superdobrador de Playground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

Na verdade, eu posso fazer todo tipo de coisa:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

Por que isso funciona? Eu pensei que precisava haver __init__.pyarquivos (os vazios funcionariam) em ambos ae bpara module.pyserem importáveis ​​quando o caminho do Python apontar para a Playgroundpasta?

Isso parece ter mudado do Python 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

Com __init__.pyem ambos ~/Playground/ae ~/Playground/a/bfunciona bem.

Respostas:


190

O Python 3.3+ possui pacotes de espaço para nome implícito que permitem criar pacotes sem um __init__.pyarquivo.

Permitir pacotes implícitos de namespace significa que o requisito de fornecer um __init__.pyarquivo pode ser completamente eliminado e afetado ....

A maneira antiga com __init__.pyarquivos ainda funciona como no Python 2.


10
Vou ler o documento, mas é um pouco longo. É possível resumir rapidamente? Você poderia me dizer: ele ainda suporta init .py ou ignora-os completamente? Se os apoia, qual é a diferença de funcionalidade e por que essa dualidade?
Wujek

3
Portanto, o tutorial provavelmente deve ser atualizado. Um bug de documentação foi aberto para isso?
Michel Samia

4
Eu ainda estou chateado que este desafia a Zen Of Python linha 2: Explicit is better than implicit.....
JayRizzo

4
@ JayRizzo But: "Embora praticidade supere a pureza."
Mike Müller

18
@JayRizzo IMO é ainda mais explícito. Às vezes acontece fazer coisas init, outras __init__.pyvezes não. No Python 3, quando preciso dessas coisas, crio um novo __init__.pycom código específico, caso contrário, não preciso . Isso é útil para saber, visualmente, quais pacotes possuem init personalizado. Em vez disso, no python 2, sempre tenho que colocar um __init__.py(geralmente vazio), tornando um grande número deles e, finalmente, mais difícil de lembrar onde você colocou seu código de inicialização. Isso também deve se encaixar "Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazer isso".
Paolo

146

IMPORTANTE

A resposta de Mike está correta, mas é imprecisa. É verdade que o Python 3.3+ suporta pacotes de espaço para nome implícito, o que permite criar um pacote sem um __init__.pyarquivo.

Isso, no entanto, APENAS se aplica a arquivos VAZIOS__init__.py . Portanto, os arquivos VAZIOS__init__.py não são mais necessários e podem ser omitidos. Se você deseja executar um script de inicialização específico quando o pacote ou qualquer um de seus módulos ou subpacotes forem importados, você ainda precisará de um __init__.pyarquivo. Esta é uma ótima resposta do Stack Overflow para o motivo de você querer usar um __init__.pyarquivo para fazer alguma inicialização adicional, caso esteja se perguntando por que isso é útil.

Exemplo de estrutura de diretório:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

EXEMPLOS

Os exemplos abaixo demonstram como o script de inicialização é executado quando o child_packageou um de seus módulos é importado.

Exemplo 1 :

from parent_package import child_package  # prints "from parent"

Exemplo 2 :

from parent_package.child_package import child1  # prints "from parent"

2
Suponha que eu tenha o run_script.pymesmo diretório, como parent_packageposso apenas importar como from parent_package.child_package import child1sem __init__.py?
Mrgloom 16/05

O objetivo disso é que você possa escrever child_package.some_function mesmo que alguma_função esteja definida no childX.py? Em outras palavras, evita exigir que o usuário saiba sobre os diferentes arquivos no child_package? ?
johnbakers

Sim, não entendo por que você criaria child1.py, em child2.pyvez de apenas colocar o código deles em __init__.py diretamente.
binki

As declarações de importação não devem __init__ser importações relativas, ou seja from . import child1? A importação absoluto me dá ModuleNotFoundError(em Python 3.6)
Halbeard

5
Na minha experiência, mesmo com o python 3.3+, __init__.pyàs vezes ainda é necessário um vazio , como quando você deseja referenciar uma subpasta como um pacote. Por exemplo, se eu executá- python -m test.foolo, não funcionaria até criar um vazio __init__.pyna pasta de teste. E eu estou falando sobre a versão 3.6.6 aqui!
Prahlad Yeri

6

Se você possui setup.pyum projeto e o utiliza find_packages(), é necessário ter um __init__.pyarquivo em cada diretório para que os pacotes sejam encontrados automaticamente.

Os pacotes são reconhecidos apenas se incluem um __init__.pyarquivo

UPD : Se você quiser usar pacotes de namespace implícitas sem __init__.pyvocê apenas tem que usar find_namespace_packages()em vez

Documentos


1

Eu diria que um deve omitir o __init__.pyúnico se quiser ter o pacote implícito de namespace . Se você não sabe o que significa, provavelmente não o deseja e, portanto, deve continuar usando o __init__.pyeven no Python 3.

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.