2011-01-31 5 views
7

Sto cercando un modo per emulare i collegamenti simbolici per le importazioni Python. Mi piacerebbe essere in grado di decomprimere la seguente struttura delle cartelle sul posto, senza file di duplicazione:Come posso reindirizzare in modo trasparente un'importazione Python?

root 
├─ python_lib 
│ └─ my_utils 
│  ├─ __init__.py 
│  └─ etc.py 
├─ app1 
├─ app2 
└─ app3 
    ├─ lib 
    │ ├─ __init__.py 
    │ └─ my_utils.py 
    └─ run.py 

app3/run.py contiene questo:

from lib.my_utils import etc 

etc.pancakes() 

mi piacerebbe il codice per utilizzare il etc situato in python_lib/my_utils/. C'è qualcosa che posso inserire in app3/lib/my_utils.py in modo che Python> = 3.1 importerà in modo trasparente la cartella python_lib/my_utils/ (utilizzando i percorsi relativi e ..) e funzioneranno anche i pacchetti secondari?

risposta

3

È necessario aggiungere questo percorso a sys.path. Per esempio:

lib_path = os.path.abspath(os.path.split(os.getcwd()+"/"+sys.argv[0])[0]+"/../_lib/my_utils/") 
sys.path.append(lib_path) 
+0

Questo non avrebbe funzionato se messo in 'my_utils.py', dal momento che il percorso di importazione è già risolto da allora. Se lo eseguo prima del mio codice principale, non funzionerà, perché ogni subpackage in 'my_utils' apparirebbe di primo livello in Python, e quindi le importazioni relative all'interno di' my_utils' non funzionerebbero. – zildjohn01

+0

Di solito ho impostato i percorsi dal mio script 'run'. Altrimenti non ha molto senso. Si potrebbe anche provare a giocare con la variabile d'ambiente 'PYTHONPATH'. Maggiori informazioni qui http://docs.python.org/tutorial/modules.html#the-module-search-path – Elalfer

5

Si dovrà eseguire qualcosa prima app3/run.py raggiunge l'istruzione import.

import python_lib 
import sys 
sys.modules['lib'] = python_lib 
# ... 
from lib import etc 
print etc.__file__ 
print dir(etc) 
0

ho fatto le seguenti modifiche alla struttura di directory per semplificare l'esempio:

  • creare root root/python_lib/__ init__.py
  • rinominare/python_lib di root/lib
  • sostituire root/app3/lib/con lib.py

Inserire il seguente codice in root/app3/lib.py

import os 
import sys 

pth = os.path.sep.join(sys.argv[0].split(os.path.sep)[0:-2]) 
sys.path.insert(0, pth) 
del sys.modules[__name__] 
import lib 

In sostanza, abbiamo un modulo fittizio che sostituisce il proprio riferimento in sys.modules con un riferimento a un modulo o pacchetto in un'altra posizione.

0

Che ne dici di questo? (Sì, metterlo a app3/lib/my_utils.py.)

import os 
_f = os.path.realpath(__file__) 
_f = os.path.dirname(_f) 
_f = os.path.dirname(_f) 
_f = os.path.dirname(_f) 
_f = os.path.join(_f, 'python_lib') 
def f(): 
    path = sys.path 
    path.insert(0, _f) 
    sys.modules['lib.my_utils'] = __import__('my_utils') 
    path.pop(0) 
f() 
1

Aggiungere __init__.py alla cartella python_lib app3/run.py contiene

import python_lib.my_utils 
import os 

sys.modules['lib.my_utils'] = python_lib.my_utils 
-1

molto tardi per questo, ma questo è incredibilmente facile. Tutto quello che devi fare è modificare l'attributo __path__ del tuo pacchetto in modo che punti alla cartella in cui si trovano i tuoi moduli. Ciò richiede che lib sia un pacchetto, non solo un modulo (ad esempio una cartella con un __init__.py). Per impostazione predefinita, __path__ è un elenco di elementi che contiene il percorso della cartella che è il pacchetto - ['/path/to/lib']. Significato, che per impostazione predefinita, Python cerca i sottomoduli nella cartella del modulo (sembra una cosa molto logica da fare).

È possibile modificare il contenuto del percorso in modo che punti dove si desidera, ma deve contenere percorsi assoluti. Se solo aggiungipath/to/lib_python allora python cercherà prima lib, trova my_utils.py e poi si ferma. In tal caso sarà necessario eliminare my_utils.py o inserire il nuovo percorso nella parte anteriore di __path__ in modo tale che prima venga effettuata la ricerca della posizione.Ciò significa anche che la cartella lib può contenere i propri moduli supplementari per le librerie condivise e continuare a funzionare.

In pratica:

lib/__ init__.py

from os.path import join 
__path__.insert(0, join(__path__[0], "..", "..", "python_lib")) 
Problemi correlati