Importazione da un percorso relativo in Python


Risposte:


142

EDIT Nov 2014 (3 anni dopo):

Python 2.6 e 3.x supportano le importazioni relative corrette, in cui puoi evitare di fare qualsiasi cosa hacky. Con questo metodo, sai che stai ottenendo un'importazione relativa piuttosto che un'importazione assoluta . Il ".." significa, vai alla directory sopra di me:

from ..Common import Common

Come avvertimento, questo funzionerà solo se esegui il tuo python come un modulo, dall'esterno del pacchetto. Per esempio:

python -m Proj

Modo hacky originale

Questo metodo è ancora comunemente usato in alcune situazioni, dove in realtà non stai mai "installando" il tuo pacchetto. Ad esempio, è popolare tra gli utenti Django.

Puoi aggiungere Common / al tuo sys.path (l'elenco dei percorsi che Python guarda per importare le cose):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) ti dà solo la directory in cui si trova il tuo file python corrente, quindi andiamo a 'Common /' la directory e importiamo 'Common' il modulo.


2
Non modificare manualmente il percorso dei moduli Python, potrebbe essere solo per hack rapidi. Imparare la gestione dei pacchetti Python usando distutils, setuptools ecc. Di solito è un'abilità richiesta che risolverà problemi del genere.
Sascha Gottfried

1
@SaschaGottfried è totalmente d'accordo, anche se se non stai creando un pacchetto distribuibile, probabilmente non avrà importanza. Ad esempio, in Django non installate mai realmente la vostra app con distutils, quindi il metodo sopra è un trucco facile. Ma comunque ho modificato la risposta con quello che avrei fatto in questi giorni.
Dave

33
Grazie per aver risposto alla vera domanda invece di predicare la tecnica corretta. Ci sono molte buone ragioni per fare importazioni relative.
toporagno

come saliresti più di un livello?
jxramos

10
per salire di un livello in più, usa un punto aggiuntivo per ogni livello. @jxramos ex: from ...myfileva a../../myfile
WattsInABox

10

Abbastanza divertente, lo stesso problema che ho appena incontrato e ottengo questo lavoro nel modo seguente:

combinando con il comando linux ln, possiamo rendere le cose molto più semplici:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

E ora se vuoi importare some_stuffda file: Proj/Common/Common.pynel tuo file:, Proj/Client/Client.pyproprio in questo modo:

# in Proj/Client/Client.py
from Common.Common import some_stuff

E lo stesso vale per Proj/Server, Funziona anche per il setup.pyprocesso, la stessa domanda discussa qui , spero che aiuti!


10

Non eseguire un'importazione relativa.

Da PEP8 :

Le importazioni relative per le importazioni all'interno di un pacchetto sono fortemente scoraggiate.

Metti tutto il tuo codice in un super pacchetto (es. "Miaapp") e usa i sottopacchetti per client, server e codice comune.

Aggiornamento: " Python 2.6 e 3.x supporta le importazioni relative corrette (...) ". Vedi le risposte di Dave per maggiori dettagli.


1
Immagina di aggiungere del codice alla fine del client e del server dopo la if __name__ == "__main__":riga " ". Cioè, vuoi essere in grado di usarli come script autonomi. Come farlo correttamente? Penso che sia un caso d'uso perfettamente comune che dovrebbe essere supportato. Perché è scoraggiato?
Jabba

83
Sono sorpreso che "Non farlo" sia la risposta accettata per una domanda "come faccio ..." (beh, ad eccezione di Rails <g>.) Ci sono ragioni occasionali per farlo. Uso una soluzione simile a quella che suggerisce Dave.
Tom Wilson

1
@TomWilson: Non è pura risposta "non farlo". C'è "fallo in questo modo" di seguito.
Michał Šrajer

2
Qualcuno dovrebbe dirlo ai ragazzi di Numpy! Usano una tonnellata di importazioni relative!
Austin A

12
Questa risposta non è applicabile alle versioni correnti di Python. La parte citata non si trova più in PEP 8. Al giorno d'oggi si legge come: "le importazioni relative esplicite sono un'alternativa accettabile alle importazioni assolute, specialmente quando si ha a che fare con layout di pacchetti complessi in cui l'uso di importazioni assolute sarebbe inutilmente
prolisso

8

Fare un'importazione relativa è assolutamente OK! Ecco cosa fa il mio piccolo:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py

1
Ma è meglio che tu sappia dove sta effettivamente puntando sys.argv [0] - (probabilmente) non è la directory in cui ti trovavi quando hai avviato python.
CarlH

Questo è un trucco rapido, con molte insidie. Ma la domanda non era nemmeno migliore.
Sascha Gottfried

1
Questo è scritto chiaramente, ma l'hack originale nella risposta di Dave è migliore perché utilizza __file__per ottenere la relazione corretta dal file corrente
John Neuhaus

4

Il metodo di importazione predefinito è già "relativo", da PYTHONPATH. Il PYTHONPATH è per impostazione predefinita, in alcune librerie di sistema insieme alla cartella del file sorgente originale. Se esegui con -m per eseguire un modulo, la directory corrente viene aggiunta a PYTHONPATH. Quindi, se il punto di ingresso del tuo programma è all'interno di Proj, l'utilizzo import Common.Commondovrebbe funzionare sia all'interno di Server.py che di Client.py.

Non eseguire un'importazione relativa. Non funzionerà come vorresti.


1
Se questo è vero, perché le risposte migliori non lo dicono? Funzionerà o no?
Anonimo
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.