Qualcuno può spiegare le importazioni relative di Python?


174

Non posso per la vita di me far funzionare le relative importazioni di Python. Ho creato un semplice esempio di dove non funziona:

La struttura delle directory è:

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py

/start.py contiene solo: import sub.relative

/sub/relative.py contiene solo from .. import parent

Tutti gli altri file sono vuoti.

Quando si esegue quanto segue sulla riga di comando:

$ cd /
$ python start.py

Ottengo:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

Sto usando Python 2.6. Perché è così? Come faccio a far funzionare questo esempio sandbox?

Risposte:


140

Stai importando dal pacchetto "sub". start.pynon è esso stesso in un pacchetto anche se c'è un __init__.pyregalo.

Dovresti avviare il tuo programma da una directory su parent.py:

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

Con start.py:

import pkg.sub.relative

Ora pkg è il pacchetto di livello superiore e l'importazione relativa dovrebbe funzionare.


Se vuoi restare fedele al tuo layout attuale, puoi semplicemente usare import parent. Poiché si utilizza start.pyper avviare l'interprete, la directory in cui start.pysi trova si trova nel percorso di Python. parent.pyvive lì come un modulo separato.

Puoi anche eliminare in sicurezza il livello superiore __init__.py, se non importi nulla in uno script più in alto nella struttura di directory.


2
Stai confondendo i termini 'modulo' e 'pacchetto'. 'start.py' rappresenta il modulo 'start', 'mod' e 'mod.sub' sono pacchetti, 'mod' è un pacchetto di livello superiore.
Ferdinand Beyer,

34
Grazie, ma onestamente sembra davvero sciocco. Per un linguaggio così bello, non posso credere che i designer avrebbero creato una tale limitazione. Non c'è altro modo?
Carl

2
Non è affatto sciocco. Le importazioni relative sono un mezzo per fare riferimento ai moduli di pari livello all'interno di un pacchetto. Se si desidera importare un modulo di livello superiore, utilizzare le importazioni assolute.
Ferdinand Beyer,

58
Non sciocco? Quindi in bash, non essere stato in grado di indirizzare la relativa directory superiore con ".." non ti disturberà?
e-satis

2
Mi sembra che l'idea di Python sia quella di utilizzare importazioni "assolute" dalla directory in cui è stato avviato lo script principale. Quindi puoi usare il percorso assoluto "import parent" per importare il modulo genitore dal fratello. E i relativi importano una specie di eredità o altro ...
Odisseo,

35

Se hai intenzione di chiamare relative.pydirettamente e cioè se vuoi davvero importare da un modulo di livello superiore devi aggiungerlo esplicitamente sys.pathall'elenco.
Ecco come dovrebbe funzionare:

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

Se ritieni che quanto sopra possa causare qualche tipo di incoerenza, puoi invece utilizzare questo:

sys.path.append(sys.path[0] + "/..")

sys.path[0] si riferisce al percorso da cui è stato eseguito il punto di ingresso.


3

Controllandolo in python3:

python -V
Python 3.6.5

Esempio 1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

Se lo eseguiamo in questo modo (solo per assicurarci che PYTHONPATH sia vuoto):

PYTHONPATH='' python3 start.py

Produzione:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

Se cambiamo importazione in sub/relative.py

- sub/relative.py
import parent

Se lo eseguiamo in questo modo:

PYTHONPATH='' python3 start.py

Produzione:

Hello from parent.py

Esempio 2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

Eseguilo come:

PYTHONPATH='' python3 sub/start.py

Produzione:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

Se cambiamo importazione in sub/start.py:

- sub/start.py
import relative
import parent

Eseguilo come:

PYTHONPATH='' python3 sub/start.py

Produzione:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

Eseguilo come:

PYTHONPATH='.' python3 sub/start.py

Produzione:

Hello from relative.py
Hello from parent.py

Inoltre è meglio usare l'importazione dalla cartella principale, ovvero:

- sub/start.py
import sub.relative
import parent

Eseguilo come:

PYTHONPATH='.' python3 sub/start.py

Produzione:

Hello from relative.py
Hello from parent.py
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.