Domanda

Cosa significa __init__.py in una directory sorgente di Python?

È stato utile?

Soluzione

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

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

Altri suggerimenti

I file denominati __init__.py sono usati per contrassegnare le directory sul disco come directory dei pacchetti Python. Se hai i file

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

e mydir sono sul tuo percorso, puoi importare il codice in module.py come

import spam.module

o

from spam import module

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

Il file __init__.py è generalmente vuoto, ma può essere utilizzato per esportare parti selezionate del pacchetto con un nome più conveniente, mantenere funzioni di convenienza, ecc. Dato l'esempio sopra, è possibile accedere ai contenuti del modulo init come

import spam

basato su questo

Oltre a etichettare una directory come pacchetto Python e definire __all__ , __init__.py ti consente di definire qualsiasi variabile a livello di pacchetto. In questo modo è spesso conveniente se un pacchetto definisce qualcosa che verrà importato frequentemente, in modo simile all'API. Questo modello promuove l'adesione al Pythonic "flat è meglio del nidificato" filosofia.

Un esempio

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 "database" pacchetto con alcuni moduli:

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

Il mio __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)

Dato che qui definisco Sessione , posso iniziare una nuova sessione usando la sintassi seguente. Questo codice sarebbe lo stesso eseguito dall'interno o dall'esterno del "database" directory del pacchetto.

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 avviare nuove sessioni utilizzando:

from database.create_session import Session
session = Session()

Ulteriori letture

Esiste 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_

L'opinione della maggioranza sembra essere che i file __init__.py dovrebbero essere molto sottili per evitare di violare l'espressione " esplicita è meglio che implicita " filosofia.

Esistono 2 motivi 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 () di

    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 più alto):

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

Il file __init__.py 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.

A partire da Python 3.3, __init__.py non è più necessario per definire le directory come pacchetti Python importabili.

Controlla 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/
__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 file __init__.py 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 può anche 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 contenuto __init__.py .

Sebbene Python funzioni senza un file __init__.py , dovresti comunque includerne uno.

Specifica che un pacchetto deve essere trattato come un modulo, quindi includilo (anche se è vuoto).

Esiste anche un caso in cui è possibile utilizzare effettivamente un file __init__.py :

Immagina di avere la seguente struttura di file:

main_methods 
    |- methods.py

E method.py contenevano questo:

def foo():
    return 'foo'

Per utilizzare 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 mantenere method.py all'interno di main_methods (runtime / dipendenze per esempio) ma vuoi solo importare main_methods .


Se hai cambiato il nome di method.py in __init__.py , puoi usare foo () semplicemente importando main_methods :

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

Funziona perché __init__.py è trattato come parte del pacchetto.


Alcuni pacchetti Python lo fanno effettivamente. Un esempio è con JSON , dove è in esecuzione import json sta effettivamente importando __init__.py dal pacchetto json ( vedi 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, inserisco qui il commento dell'alchimista a due bit .

$ 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 (dire cose) contenente altri file PY, puoi fare qualcosa come import stuff.other.

root\
    stuff\
         other.py

    morestuff\
         another.py

Senza questo __init__.py all'interno della directory directory, non è possibile importare other.py, perché Python non sa dove si trova il codice sorgente per stuff e non è in grado di riconoscerlo come pacchetto .

Un file __init__.py semplifica l'importazione. Quando un __init__.py è presente all'interno di un pacchetto, la funzione a () può essere importata dal file b.py in questo 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top