2010-09-01 11 views
26

Uso delle importazioni rispetto a Python ha uno svantaggio, non sarà in grado di eseguire i moduli come standalone più perché si otterrà un'eccezione: ValueError: Attempted relative import in non-packageCome utilizzare correttamente le importazioni relative o assolute nei moduli Python?

# /test.py: just a sample file importing foo module 
import foo 
... 

# /foo/foo.py: 
from . import bar 
... 
if __name__ == "__main__": 
    pass 

# /foo/bar.py: a submodule of foo, used by foo.py 
from . import foo 
... 
if __name__ == "__main__": 
    pass 

Come devo modificare il codice di esempio in modo da essere in grado di eseguire tutti: test.py, foo.py e bar.py

Sto cercando una soluzione che funzioni con python 2.6+ (incluso 3.x).

+1

Controllare questo thread: http://www.velocityreviews.com/forums/t502905-relative-import-broken.html –

+0

Grazie, sfortunatamente, ero a conoscenza di questo thread precedente ma non ho trovato alcuna soluzione al problema. Finora ho visto solo molte persone lamentarsi di questo. Abbiamo bisogno di una chiara soluzione/esempio per questo problema. – sorin

+0

Correlati: [Come sapere se lo script python è stato eseguito usando l'opzione -m dell'interprete?] (Http://stackoverflow.com/questions/8348726/) –

risposta

16

In primo luogo, presumo che tu abbia realizzato che ciò che hai scritto avrebbe comportato un problema di importazione circolare, perché foo importa la barra e viceversa; tenta di aggiungere

from foo import bar 

a test.py, e vedrete che non riesce. L'esempio deve essere cambiato per funzionare.

Quindi, quello che stai chiedendo è davvero di fallback all'importazione assoluta quando l'importazione relativa fallisce; infatti, se esegui foo.py o bar.py come modulo principale, gli altri moduli si troveranno al livello di root e se condividono il nome con un altro modulo sul sistema, quale sarà selezionato dipende da l'ordine in sys.path. Poiché la directory corrente è solitamente la prima, i moduli locali verranno selezionati se disponibili, ad esempio, se hai un file "os.py" nella directory di lavoro corrente, verrà selezionato al posto di quello incorporato.

Un possibile suggerimento è:

foo.py

try: 
    from . import bar 
except ValueError: 
    import bar 

if __name__ == "__main__": 
    pass 

bar.py:

if __name__ == "__main__": 
    pass 

A proposito chiamando script dalla posizione corretta è di solito modo migliore.

python -m foo.bar 

Probabilmente è il modo migliore per andare. Questo runs the module as a script.

+0

Non penso che la 'barra di importazione' nell'istruzione 'except' funzionerà per Python 3.1+ – John

+0

@John, per quanto posso dire, non c'è motivo perché l'importazione in eccetto non dovrebbe funzionare. Funziona al 100% in Python 3.2. –

-2

Finora l'unica soluzione che ho trovato era di non utilizzare affatto le importazioni relative.

A causa della limitazione attuale, mi chiedo quando qualcuno dovrebbe utilizzare le importazioni relative in Python.

Su tutte le configurazioni che ho utilizzato il sys.path conteneva la directory corrente come primo argomento, quindi utilizzare solo import foo anziché from . import foo perché farà lo stesso.

+3

Ma ciò causerà problemi quando si decide di utilizzare un modulo standard o di terze parti python con lo stesso nome di un modulo nel pacchetto. Ecco perché IMHO è molto meglio usare "da __future__ import absolute_import' e relative importazioni. –

22

Si può solo iniziare 'per eseguire i moduli come standalone' in un po 'un modo diverso:

Invece di:

python foo/bar.py 

Usa:

python -mfoo.bar 

Naturalmente, il Il file foo/__init__.py deve essere presente.

Si noti inoltre che si ha una dipendenza circolare tra foo.py e bar.py - questo non funzionerà. Immagino sia solo un errore nel tuo esempio.

Aggiornamento: sembra che funziona perfettamente anche usare questo come la prima linea del foo/bar.py:

#!/usr/bin/python -mfoo.bar 

Quindi è possibile eseguire lo script direttamente nei sistemi POSIX.

+3

Questo è un brutto trucco che considero inaccettabile, specialmente perché rende molto più difficile eseguirli (specialmente su Windows) – sorin

+0

A proposito, l'esempio di bogdan funzionava, anche con l'importazione circolare. – sorin

+15

+1, questo è esattamente il modo giusto per "eseguire autonomamente" un modulo ** come parte di un pacchetto ** (che è necessario, se si desidera utilizzare le importazioni relative, ovviamente). –

0

Perché non inserire semplicemente "principale" in un diverso file .py?

1

Importazione relativa di Ditch: si dovrebbe comunque considerare lo spazio dei nomi del pacchetto come globale.

Il trucco per rendere questo appetibile è la modifica sys.path in modo appropriato. Ecco alcuni spunti di riflessione:

 
# one directory up 
_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 
sys.path.insert(0, _root_dir)for now 
+4

-1. Non abbandonare le importazioni relative; sono stati considerati validi quando la funzione di importazione assoluta è stata progettata http://mail.python.org/pipermail/python-dev/2003-December/041065.html e oggi sono perfetti. – bignose

1

In ogni cartella è necessario __init__.py.

importazione relativa funziona solo quando lo si fa:

python test.py 

importazioni test.py foo.py e foo.py può importare nulla relativa dalla cartella di test.py e superiori.

Non si può fare:

cd foo 
python foo.py 
python bar.py 

Non funzionerà mai.

È possibile provare la soluzione sys.path.append o sys.path.insert ma si rovinano i percorsi e si avranno problemi con f = open (nome file).

Problemi correlati