__Init__.py non è richiesto per i pacchetti in Python 3.3+?


195

Sto usando Python 3.5.1. Ho letto il documento e la sezione del pacchetto qui: https://docs.python.org/3/tutorial/modules.html#packages

Ora ho la seguente struttura:

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

module.py:

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

Ora, mentre in /home/wujek/Playground:

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

Allo stesso modo, ora a casa, supercartella di Playground:

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

In realtà, posso fare tutti i tipi di cose:

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

Perché funziona? Pensavo che ci fossero dei __init__.pyfile (quelli vuoti avrebbero funzionato) in entrambi ae bper module.pyessere impraticabili quando il percorso di Python punta alla Playgroundcartella?

Questo sembra essere cambiato da 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

Con __init__.pyin entrambi ~/Playground/ae ~/Playground/a/bfunziona bene.

Risposte:


192

Python 3.3+ ha pacchetti di spazi dei nomi impliciti che gli consentono di creare pacchetti senza un __init__.pyfile.

Consentire pacchetti di spazi dei nomi impliciti significa che il requisito di fornire un __init__.pyfile può essere eliminato completamente e interessato ...

Il vecchio modo con i __init__.pyfile funziona ancora come in Python 2.


10
Leggerò il documento, ma è un po 'lungo. È possibile riassumere rapidamente? Potresti semplicemente dirmi: supporta ancora init .py o li ignora completamente? Se li supporta, qual è la differenza in termini di funzionalità e perché questa dualità?
wujek,

3
Quindi il tutorial dovrebbe essere probabilmente aggiornato. È stato aperto un bug di documentazione?
Michel Samia,

4
Sono ancora sconvolto dal fatto che questo sfida la Zen Of Python linea 2: Explicit is better than implicit.....
JayRizzo,

5
@JayRizzo Ma: "Anche se la praticità batte la purezza."
Mike Müller,

19
@JayRizzo IMO è ancora più esplicito. A volte capita di fare cose init __init__.py, a volte no. In Python 3 quando ho bisogno di queste cose, ne creo una nuova __init__.pycon un codice specifico, altrimenti no. Questo è utile per sapere visivamente quali pacchetti hanno un init personalizzato. Invece in Python 2 devo sempre posizionare un __init__.py(spesso vuoto), facendone un gran numero e infine più difficile ricordare dove hai inserito il tuo codice di inizializzazione. Questo dovrebbe anche adattarsi "Dovrebbe esserci uno - e preferibilmente solo un - modo evidente di farlo.".
Paolo

148

IMPORTANTE

@La risposta di Mike è corretta ma troppo imprecisa. È vero che Python 3.3+ supporta pacchetti di spazi dei nomi impliciti che gli consentono di creare un pacchetto senza un __init__.pyfile.

Questo, tuttavia, si applica SOLO ai file VUOTI__init__.py . Quindi i file EMPTY__init__.py non sono più necessari e possono essere omessi. Se si desidera eseguire un particolare script di inizializzazione quando vengono importati il ​​pacchetto o uno dei suoi moduli o sotto-pacchetti, è comunque necessario un __init__.pyfile. Questa è un'ottima risposta Stack Overflow per il motivo per cui vorresti usare un __init__.pyfile per fare qualche ulteriore inizializzazione nel caso ti chiedessi perché questo sia in qualche modo utile.

Esempio di struttura di directory:

  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")

ESEMPI

Gli esempi seguenti mostrano come viene eseguito lo script di inizializzazione quando child_packageviene importato uno dei suoi moduli.

Esempio 1 :

from parent_package import child_package  # prints "from parent"

Esempio 2 :

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

2
Supponiamo di avere run_script.pynella stessa directory parent_packagecosì posso solo importare come from parent_package.child_package import child1senza __init__.py?
mrgloom,

Lo scopo è quindi di scrivere child_package.some_function anche se some_function è definito in childX.py? In altre parole, evita di richiedere all'utente di conoscere i diversi file in child_package? ?
johnbakers,

Sì, non capisco perché lo faresti child1.py, child2.pyinvece di mettere semplicemente il loro codice in __init__.py direttamente.
binki,

Le dichiarazioni di importazione non dovrebbero __init__essere relative importazioni cioè from . import child1? L'importazione assoluta mi dà ModuleNotFoundError(in Python 3.6)
Halbeard,

5
Nella mia esperienza, anche con Python 3.3+, a __init__.pyvolte è ancora necessario un vuoto , come quando si desidera fare riferimento a una sottocartella come pacchetto. Ad esempio, se eseguo python -m test.foonon ha funzionato fino a quando non ho creato uno spazio vuoto __init__.pynella cartella test. E sto parlando della versione 3.6.6 qui!
Prahlad Yeri,

7

Se hai setup.pynel tuo progetto e lo usi al find_packages()suo interno, è necessario avere un __init__.pyfile in ogni directory per trovare automaticamente i pacchetti.

I pacchetti sono riconosciuti solo se includono un __init__.pyfile

UPD : Se si desidera utilizzare i pacchetti di spazio dei nomi impliciti senza __init__.pyutilizzare find_namespace_packages()invece

Documenti


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.