A cosa serve __init__.py?


Risposte:


1456

Era una parte obbligatoria di un pacchetto ( vecchio "pacchetto regolare" pre-3.3 , non più nuovo "pacchetto spazio dei nomi 3.3+" ).

Ecco la documentazione.

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__.pyfile. Quando viene importato un pacchetto regolare, questo __init__.pyfile viene eseguito implicitamente e gli oggetti che definisce sono associati ai nomi nello spazio dei nomi del pacchetto. Il __init__.pyfile 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.


187
Cosa significa: "questo viene fatto per impedire alle directory con un nome comune, come stringa, di nascondere involontariamente moduli validi che si verificano in seguito nel percorso di ricerca del modulo"?
Carl G,

97
@CarlG Python cerca in un elenco di directory per risolvere i nomi, ad esempio nelle istruzioni di importazione. Dato che possono essere di qualsiasi directory e l'utente può aggiungere arbitrarie all'utente, gli sviluppatori devono preoccuparsi delle directory che condividono un nome con un modulo Python valido, come 'stringa' nell'esempio di documenti. Per alleviare ciò, ignora le directory che non contengono un file chiamato _ _ init _ _.py (senza spazi), anche se è vuoto.
Two-Bit Alchemist

186
@CarlG Prova questo. Crea una directory chiamata 'datetime' e in essa crea due file vuoti, il file init.py (con caratteri di sottolineatura) e datetime.py. Ora apri un interprete, importa il sistema e il problema 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.
Two-Bit Alchemist

4
@ DarekNędza Hai qualcosa che non è stato impostato correttamente se non riesci ad aprire un interprete Python e rilasciarlo from datetime import datetimesenza errori. Va bene fino alla versione 2.3!
Two-Bit Alchemist

5
@SWang: Non è corretto: builtinselenca 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 ).
Maggyero,

843

I file denominati __init__.pyvengono 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.pyas

import spam.module

o

from spam import module

Se rimuovi il __init__.pyfile, Python non cercherà più i sottomoduli all'interno di quella directory, quindi i tentativi di importare il modulo falliranno.

Il __init__.pyfile è 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


96
Aggiornamento: il file __init__.pyera 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.
Rob_before_edits,

4
Non usarlo. È un pacchetto "namespace", non un pacchetto normale. Il pacchetto namespace è usato per casi d'uso molto rari. Potrebbe non essere necessario sapere quando utilizzarlo. Basta usare __init__.py.
metano,

2
tuttavia se lo hai setup.pye lo usi find_packages()è necessario averlo __init__.pyin ogni directory. Vedere stackoverflow.com/a/56277323/7127824
techkuz

484

Oltre a etichettare una directory come pacchetto Python e definire __all__, __init__.pyconsente 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.

Un esempio

Ecco un esempio di uno dei miei progetti, in cui spesso frequento un sessionmakerchiamato Sessionper interagire con il mio database. Ho scritto un pacchetto "database" con alcuni moduli:

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

My __init__.pycontiene 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 Sessionqui, 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 Sessionin 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()

Ulteriori letture

C'è un thread reddit piuttosto interessante che copre gli usi appropriati di __init__.pyqui:

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__.pyfile dovrebbero essere molto sottili per evitare di violare la filosofia "esplicito è meglio che implicito".


3
engine, sessionmaker, create_engine, E ospuò tutto anche essere importati da databaseora ... sembra di aver fatto un pasticcio di quel namespace.
ArtOfWarfare il

9
@ArtOfWarfare, puoi usare __all__ = [...]per limitare ciò che viene importato import *. Ma a parte questo, sì, ti rimane uno spazio dei nomi di livello superiore disordinato.
Nathan Gould,

Posso sapere qual è l '"URL DATABASE"? Ho provato a replicarlo racchiudendo create_engine con 'mysql + mysqldb: // root: python @ localhost: 3306 / test' ma non funziona. Grazie.
SunnyBoiz,

2
Come accederesti alla classe 'Session' definita in init dall'interno del pacchetto, ad esempio quieries.py?
vldbnc,

253

Ci sono 2 ragioni principali per __init__.py

  1. 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
  2. Se si desidera inizializzare qualcosa; ad esempio, registrazione (che dovrebbe essere messa al livello superiore):

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

7
oh, prima di leggere la tua risposta, ho pensato che chiamare una funzione esplicitamente dalla sua posizione fosse una buona pratica.
Aerin,

2
@Aerin sarebbe meglio non considerare brevi affermazioni (o, in questo caso, conclusioni soggettive) come sempre vere. L'importazione da __init__.pypuò essere utile a volte, ma non tutte le volte.
Tobias Sette,

2
Questi codici vengono eseguiti in fase di importazione o di runtime?
user1559897

111

Il __init__.pyfile 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.


89

Da Python 3.3, __init__.pynon è 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__.pyfile 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?


3
È un pacchetto "namespace". Non usarlo per un pacchetto normale.
metano

@methan, potresti approfondire il tuo commento?
Robert Lugg,


57

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__.pyin un pacchetto. Spiegherò il __init__.pyfile 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__.pypuò 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__.pyin 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__.pycontenuto.


Come sarà il mio setup.py a fare la stessa importazione attraverso la libreria in pacchetto? from package_x.subPackage_b.module_n1 import function_X
technazi

quindi la chiave da asporto qui è "utilizzo dell'importazione *, il pacchetto del modulo è soggetto al contenuto init .py"
Minnie

54

Sebbene Python funzioni senza un __init__.pyfile, 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__.pyfile:

Immagina di avere la seguente struttura di file:

main_methods 
    |- methods.py

E methods.pyconteneva 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.pydentro main_methods(runtime / dipendenze per esempio) ma vuoi solo importare main_methods.


Se è stato modificato il nome methods.pyper __init__.pyallora si potrebbe usare foo()semplicemente importando main_methods:

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

Questo funziona perché __init__.pyviene trattato come parte del pacchetto.


Alcuni pacchetti Python lo fanno effettivamente. Un esempio è con JSON , dove l'esecuzione import jsonsta effettivamente importando __init__.pydal jsonpacchetto ( vedere la struttura del file del pacchetto qui ):

Codice sorgente: Lib/json/__init__.py


39

__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
>>> 

30

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__.pyall'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.


2
Ho la stessa struttura nel mio progetto (python 3.4) ma non sono in grado di far vedere a Another.py other.py. Come devo effettuare l'importazione? da root.stuff importa altro? Funziona in modalità debug VSCode ma non nella riga di comando. Qualche idea?
Rodrigorf,

10

Un __init__.pyfile semplifica l'importazione. Quando un __init__.pyè presente all'interno di un pacchetto, la funzione a()può essere importata dal file in questo b.pymodo:

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

cosa intendi con "la funzione a () può essere importata dal file b.py [snippet] Senza di essa, tuttavia, non puoi importare direttamente. "? Posso importare la funzione a () dal file b.py senza __init__.py.
aderchox,
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.