Risposte:
Era una parte obbligatoria di un pacchetto ( vecchio "pacchetto regolare" pre-3.3 , non più nuovo "pacchetto spazio dei nomi 3.3+" ).
Python definisce due tipi di pacchetti, pacchetti regolari e pacchetti di spazi dei nomi. I pacchetti regolari sono pacchetti tradizionali come esistevano in Python 3.2 e precedenti. Un pacchetto normale viene in genere implementato come una directory contenente un
__init__.py
file. Quando viene importato un pacchetto regolare, questo__init__.py
file viene eseguito implicitamente e gli oggetti che definisce sono associati ai nomi nello spazio dei nomi del pacchetto. Il__init__.py
file può contenere lo stesso codice Python che può contenere qualsiasi altro modulo e Python aggiungerà alcuni attributi aggiuntivi al modulo quando viene importato.
Ma basta fare clic sul collegamento, contiene un esempio, ulteriori informazioni e una spiegazione dei pacchetti dello spazio dei nomi, il tipo di pacchetti senza __init__.py
.
sys.path.insert(0, '/path/to/datetime')
, sostituendo quel percorso con il percorso in qualunque directory tu abbia appena creato. Ora prova qualcosa del genere from datetime import datetime;datetime.now()
. Dovresti ottenere un AttributeError (perché sta importando il tuo file vuoto ora). Se dovessi ripetere questi passaggi senza creare il file init vuoto, ciò non accadrebbe. Questo è ciò che è destinato a prevenire.
from datetime import datetime
senza errori. Va bene fino alla versione 2.3!
builtins
elenca le funzioni e le classi integrate, non i moduli integrati (cfr. Docs.python.org/3/tutorial/modules.html#the-dir-function ). Se vuoi elencare i moduli integrati , fallo import sys; print(sys.builtin_module_names)
(vedi docs.python.org/3/library/sys.html#sys.builtin_module_names ).
I file denominati __init__.py
vengono utilizzati per contrassegnare le directory sul disco come directory dei pacchetti Python. Se hai i file
mydir/spam/__init__.py
mydir/spam/module.py
ed mydir
è sul tuo percorso, puoi importare il codice in module.py
as
import spam.module
o
from spam import module
Se rimuovi il __init__.py
file, Python non cercherà più i sottomoduli all'interno di quella directory, quindi i tentativi di importare il modulo falliranno.
Il __init__.py
file è di solito vuoto, ma può essere utilizzato per esportare porzioni selezionate del pacchetto con un nome più conveniente, contenere funzioni di convenienza, ecc. Dato l'esempio sopra, è possibile accedere al contenuto del modulo init come
import spam
basato su questo
__init__.py
era richiesto in Python 2.X ed è ancora richiesto in Python 2.7.12 (l'ho testato) ma non è più richiesto (presumibilmente) da Python 3.3 in poi, e non è richiesto in Python 3.4.3 (I testato). Consulta stackoverflow.com/questions/37139786 per maggiori dettagli.
__init__.py
.
setup.py
e lo usi find_packages()
è necessario averlo __init__.py
in ogni directory. Vedere stackoverflow.com/a/56277323/7127824
Oltre a etichettare una directory come pacchetto Python e definire __all__
, __init__.py
consente di definire qualsiasi variabile a livello di pacchetto. Fare ciò è spesso conveniente se un pacchetto definisce qualcosa che verrà importato frequentemente, in modo simile ad una API. Questo modello promuove l'adesione alla filosofia "piatta è meglio del nidificato" di Pythonic.
Ecco un esempio di uno dei miei progetti, in cui spesso frequento un sessionmaker
chiamato Session
per interagire con il mio database. Ho scritto un pacchetto "database" con alcuni moduli:
database/
__init__.py
schema.py
insertions.py
queries.py
My __init__.py
contiene il seguente codice:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Da quando ho definito Session
qui, posso iniziare una nuova sessione usando la sintassi seguente. Questo codice sarebbe lo stesso eseguito dall'interno o dall'esterno della directory del pacchetto "database".
from database import Session
session = Session()
Naturalmente, questa è una piccola comodità: l'alternativa sarebbe quella di definire Session
in un nuovo file come "create_session.py" nel mio pacchetto di database e iniziare nuove sessioni usando:
from database.create_session import Session
session = Session()
C'è un thread reddit piuttosto interessante che copre gli usi appropriati di __init__.py
qui:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
L'opinione della maggioranza sembra essere che i __init__.py
file dovrebbero essere molto sottili per evitare di violare la filosofia "esplicito è meglio che implicito".
engine
, sessionmaker
, create_engine
, E os
può tutto anche essere importati da database
ora ... sembra di aver fatto un pasticcio di quel namespace.
__all__ = [...]
per limitare ciò che viene importato import *
. Ma a parte questo, sì, ti rimane uno spazio dei nomi di livello superiore disordinato.
Ci sono 2 ragioni principali per __init__.py
Per comodità: gli altri utenti non dovranno conoscere la posizione esatta delle funzioni nella gerarchia dei pacchetti.
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
quindi altri possono chiamare add () da
from your_package import add
senza conoscere file1, come
from your_package.file1 import add
Se si desidera inizializzare qualcosa; ad esempio, registrazione (che dovrebbe essere messa al livello superiore):
import logging.config
logging.config.dictConfig(Your_logging_config)
__init__.py
può essere utile a volte, ma non tutte le volte.
Il __init__.py
file fa in modo che Python tratti le directory che lo contengono come moduli.
Inoltre, questo è il primo file da caricare in un modulo, quindi è possibile utilizzarlo per eseguire il codice che si desidera eseguire ogni volta che viene caricato un modulo o specificare i sottomoduli da esportare.
Da Python 3.3, __init__.py
non è più necessario definire le directory come pacchetti Python importabili.
Verifica PEP 420: pacchetti di spazi dei nomi impliciti :
Supporto nativo per le directory dei pacchetti che non richiedono
__init__.py
file marker e possono estendersi automaticamente su più segmenti di percorso (ispirati a vari approcci di terze parti ai pacchetti dello spazio dei nomi, come descritto in PEP 420 )
Ecco il test:
$ 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
riferimenti:
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 non richiesto per i pacchetti in Python 3?
In Python la definizione di pacchetto è molto semplice. Come Java, la struttura gerarchica e la struttura delle directory sono le stesse. Ma devi avere __init__.py
in un pacchetto. Spiegherò il __init__.py
file con l'esempio seguente:
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
può essere vuoto, purché esista. Indica che la directory deve essere considerata come un pacchetto. Naturalmente, __init__.py
è anche possibile impostare il contenuto appropriato.
Se aggiungiamo una funzione in module_n1:
def function_X():
print "function_X in module_n1"
return
Dopo l'esecuzione:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Quindi abbiamo seguito il pacchetto della gerarchia e chiamato module_n1 la funzione. Possiamo usare __init__.py
in subPackage_b in questo modo:
__all__ = ['module_n2', 'module_n3']
Dopo l'esecuzione:
>>>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
Quindi, usando * l'importazione, il pacchetto del modulo è soggetto al __init__.py
contenuto.
from package_x.subPackage_b.module_n1 import function_X
Sebbene Python funzioni senza un __init__.py
file, dovresti comunque includerne uno.
Specifica che un pacchetto deve essere trattato come un modulo, quindi includerlo (anche se è vuoto).
Esiste anche un caso in cui è possibile utilizzare effettivamente un __init__.py
file:
Immagina di avere la seguente struttura di file:
main_methods
|- methods.py
E methods.py
conteneva questo:
def foo():
return 'foo'
Per utilizzarlo foo()
è necessario uno dei seguenti:
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()
Forse lì hai bisogno (o vuoi) di tenerti methods.py
dentro main_methods
(runtime / dipendenze per esempio) ma vuoi solo importare main_methods
.
Se è stato modificato il nome methods.py
per __init__.py
allora si potrebbe usare foo()
semplicemente importando main_methods
:
import main_methods
print(main_methods.foo()) # Prints 'foo'
Questo funziona perché __init__.py
viene trattato come parte del pacchetto.
Alcuni pacchetti Python lo fanno effettivamente. Un esempio è con JSON , dove l'esecuzione import json
sta effettivamente importando __init__.py
dal json
pacchetto ( vedere la struttura del file del pacchetto qui ):
Codice sorgente:
Lib/json/__init__.py
__init__.py
tratterà la directory in cui si trova come un modulo caricabile.
Per le persone che preferiscono leggere il codice, ho inserito qui il commento di Two-Bit Alchemist .
$ 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
>>>
Facilita l'importazione di altri file Python. Quando hai inserito questo file in una directory (ad esempio cose) contenente altri file PY, puoi fare qualcosa come importare stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Senza questo __init__.py
all'interno della directory stuff, non potresti importare other.py, perché Python non sa dove si trova il codice sorgente per stuff e non è in grado di riconoscerlo come pacchetto.
Un __init__.py
file semplifica l'importazione. Quando un __init__.py
è presente all'interno di un pacchetto, la funzione a()
può essere importata dal file in questo b.py
modo:
from b import a
Senza di essa, tuttavia, non è possibile importare direttamente. Devi modificare il percorso di sistema:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a