2011-12-06 8 views
5

Ho il mio codice Python in una cartella chiamata "project", quindi i miei file di codice sono in project/*. Py. Voglio avere sottomoduli al suo interno, ad es.organizzazione del modulo pythonic - come fare riferimento ai file nella directory principale?

project/code.py # where code lives 
project/mymodule1 # where more code lives 
project/mymodule2 

ogni directory modulo ha la sua init di file .py, per esempio

project/mymodule1/__init__.py 

supponiamo di avere un file "test.py" entro myModule1 (progetto/myModule1/test.py) e mi piacerebbe fare riferimento a qualcosa da "codice", per esempio importare la funzione "myfunc"

== project/mymodule1/test.py == 
from code import myfunc 

il problema è che "codice" non verrà trovato meno che l'utente ha posto la directory "progetto /" nel loro PYTHONPATH. C'è un modo per evitarlo e utilizzare una sorta di "percorso relativo" per importare myfunc, ad es.

from ../code import myfunc 

in fondo, io non voglio obbligare gli utenti del codice per modificare il PYTHONPATH a meno che non posso farlo a livello di codice per loro da dentro il mio script. Mi piacerebbe che funzionasse fuori dagli schemi.

Come si può fare? o la soluzione è buona: alterare PYTHONPATH a livello di codice, o più idealmente, riferendosi al "codice" usando un qualche tipo di importazione relativa, poiché anche se non so dove "project/code.py" risiede sul computer dell'utente, so dove è relativo a "myfunc".

MODIFICA: Qualcuno può mostrare un esempio corretto dell'importazione intra-pacchetto? Ho cercato, da "myModule1" da fare:

from .. import foo 

dove "foo" è in code.py, ma non funziona. Ho init .py in myModule1, quindi:

project/code.py 
project/mymodule1/__init__.py 
project/mymodule1/module1_code.py 

dove module1_code.py cerca di importare foo, una funzione definita in "code.py".

EDIT: La confusione principale che ho ancora è che, anche dopo l'adozione l'esempio dato in risposta al mio messaggio, che mostra la gerarchia del progetto/sub1/test, si può ancora "cd" in sub1 e fare "python test.py "e farlo funzionare. L'utente deve essere nella directory contenente "project" e fare "import project.sub1.test". Mi piacerebbe che funzionasse a prescindere dalla directory in cui si trova l'utente. L'utente in questo caso deve eseguire il file "test.py", che vive in project/sub1 /. Quindi il banco di prova è:

$ cd project/sub1 
$ python test.py 

che produce l'errore:

ValueError: Attempted relative import in non-package 

come può essere fisso?

grazie.

+0

'code.py' importa anche' mymodule1/test.py'? Se è così, vorrai guardare a riorganizzare il tuo codice. Le importazioni circolari dovrebbero essere evitate se possibile. – Wilduck

risposta

3

Ciò è possibile in Python 2.5 e versioni successive. Vedi i documenti su Intra-Package References.

Un paio di cose da notare:

Se si intende per gli utenti di installare il pacchetto da qualche parte, per esempio usando Distutils o setuptools, quindi project saranno probabilmente già nel percorso di ricerca, e si può cambia l'importazione relativa a from project.code import ... o simile.

Nel caso in cui gli utenti stanno installando il pacchetto in una directory non standard (ad esempio, la loro home directory, da qualche altra parte che non è in sys.path, ecc), la mia opinione è che si porta a meno confusione per istruire l'utente modificare PYTHONPATH anziché modificare a livello di codice sys.path.

Nel caso in cui non si intenda che i propri utenti installino il proprio codice, ad esempio, semplicemente decodificano la sorgente, eseguendo il comando cd nella directory principale di project ed eseguendo uno script, quindi intra i riferimenti del pacchetto e le importazioni relative funzioneranno probabilmente bene.

EDIT: per ogni richiesta, ecco un esempio:

Supponiamo disposizione del pacchetto è la seguente:

project/ 
    __init__.py (empty) 
    code.py 
    sub1/ 
     __init__.py (empty) 
     test.py 

Ora, il contenuto di project/code.py sono:

# code.py (module that resides in main "project" package) 

def foo(): 
    print "this is code.foo" 

E, il contenuto di project/sub1/test.py è:

# test.py (module that resides in "sub1" subpackage of main "project" package) 

from ..code import foo 
foo() 

Quindi, test.py importa il nome foo dal percorso relativo ..code, che utilizza i riferimenti intra-pacchetto di farci tornare al modulo code.py all'interno del genitore (che è la parte ..) del pacchetto sub1.test dove siamo in esecuzione da.

Per verificare questa:

shell$ (cd to directory where "project" package is located) 
shell$ python 
Python 2.6.1 (r261:67515, Aug 2 2010, 20:10:18) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import project.sub1.test 
this is code.foo 

Nota che il doppio punto nella sintassi from .. import X solo si ottiene al pacchetto padre, ma è possibile specificare i moduli all'interno di quel pacchetto.

In altre parole, from .. import X in questo caso è equivalente a from project import X, e quindi X deve essere un modulo in project o una classe/funzione/nome all'interno project/__init__.py.

Pertanto, from ..code import X equivale a from project.code import X.

+0

Qualcuno può mostrare un esempio di importazione intra-pacchetto? Ho provato, da "mymodule1" a fare: from .. import foo, dove "foo" è in code.py ma non funziona. Ho __init__.py in mymodule1 – user248237dfsf

+0

@ user248237: vedere la mia risposta modificata incluso un esempio. La differenza principale è che 'from .. import foo' equivale alla ricerca di' project/__ init __. Py', non 'code.py'. – bjlaub

+1

quello che non capisco è perché se si cd in "sub1" e si fa: python test.py, si ottiene l'errore "ValueError: Tentativo importazione relativa in non-package" – user248237dfsf

1

il modo migliore per evitare questo è quello di mantenere tutto il codice in una cartella src o meglio chiamarlo sul progetto, ad es.myproject e mantenere un __init__.py lì, in modo da poter fare questo

from myproject import code 

modo la struttura delle cartelle sarebbe

project 
    main.py 
    myproject 
     __init__.py 
     code.py 
     module1 
     module2 

main.py o qualsiasi altro nome dare non dovrebbe avere molto codice, si dovrebbe ottenere il modulo richiesto da myproject ed eseguirlo ad es

from myproject import myapp 
myapp.run() 

vedere un buon article su come organizzare il vostro progetto di pitone.

+0

che non risolve il problema - come la chiamata di codice di module1 può essere definita a monte? in dirs padre? – user248237dfsf

+0

myproject sarà in path python e everymodule può importare qualsiasi modulo, ad es. 'da myproject.module1 import xxx' –

+0

1) Penso che tu intenda che 'project' sarà in PYTHONPATH, non 'myproject', e (2) No non lo farà se il processo è stato avviato usando 'python myproject/code.py' , che è la situazione dell'OP. La sua domanda è ancora irrisolta, IMHO –

Problemi correlati