Importazioni relative - ModuleNotFoundError: nessun modulo denominato x


179

Questa è la prima volta che mi sono davvero seduto e ho provato Python 3, e sembra fallire miseramente. Ho i seguenti due file:

  1. test.py
  2. config.py

config.py ha alcune funzioni definite in esso e alcune variabili. L'ho ridotto a quanto segue:

config.py

debug = True

test.py

import config
print (config.debug)

Ho anche un __init__.py

Tuttavia, visualizzo il seguente errore:

ModuleNotFoundError: No module named 'config'

Sono consapevole che la convenzione py3 prevede l'utilizzo di importazioni assolute:

from . import config

Tuttavia, questo porta al seguente errore:

ImportError: cannot import name 'config'

Quindi non so cosa fare qui ... Qualsiasi aiuto è molto apprezzato. :)


Non riesco a riprodurre l'errore, come si esegue questo codice?
Copperfield,

2
Lo eseguo con il minimo che viene fornito con Python, e anche come python test.py, e funziona perfettamente bene. Non ho pyCharm, ma forse è una cattiva configurazione di pyCharm che sta causando il problema
Copperfield

1
Molto strano. Sto usando WinPython - basta scaricare Python 3.6 vanilla da python.org e funziona benissimo. Non ho mai pensato di controllare l'interprete! Grazie!
Blitzmann,

1
La mia ipotesi è che qualcosa di strano stia succedendo con PYTHONPATH. Controlla le impostazioni IDE e / o le variabili di ambiente del sistema.
Martin Tournoij,

1
Ho lo stesso identico problema. Non è pycharm! È python3. Funziona in python2, ma quando si utilizza python3, viene visualizzato questo errore! molto frustrante.

Risposte:


164

TL; DR: non è possibile effettuare importazioni relative dal file eseguito poiché il __main__modulo non fa parte di un pacchetto.

Importazioni assolute : importa qualcosa disponibile susys.path

Importazioni relative : importa qualcosa rispetto al modulo corrente, deve far parte di un pacchetto

Se esegui entrambe le varianti esattamente nello stesso modo, una di esse dovrebbe funzionare. Comunque, ecco un esempio che dovrebbe aiutarti a capire cosa sta succedendo, aggiungiamo un altro main.pyfile con la struttura di directory generale come questa:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

E aggiorniamo test.py per vedere cosa sta succedendo:

# config.py
debug = True


# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

Eseguiamo test.py prima:

$ python ryan/test.py
__main__
Relative import failed
True

Qui "test" è il __main__modulo e non sa nulla dell'appartenenza a un pacchetto. Tuttavia import configdovrebbe funzionare, poiché la ryancartella verrà aggiunta a sys.path.

Eseguiamo invece main.py:

$ python main.py
ryan.test
True
Absolute import failed

E qui il test è all'interno del pacchetto "ryan" e può eseguire importazioni relative. import configfallisce poiché le importazioni relative implicite non sono consentite in Python 3.

Spero che questo abbia aiutato.

PS: se stai usando Python 3 non c'è più bisogno di __init__.pyfile.


3
C'è qualcosa che posso fare per far funzionare sempre le importazioni assolute? Tipo, chiama sys.path.append('/some/path/my_module')dentro /some/path/my_module/__init__.py?
James T.

4
@JamesT. Sì, è abbastanza comune modificarlo sys.pathdurante il runtime ( github.com/… ). È inoltre possibile impostare la variabile di ambiente PYTHONPATH.
Igonato l'

6
"se stai usando Python 3 non c'è più bisogno di __init__.pyfile." Interessante. Puoi approfondire questo? Ho avuto l'impressione che il meccanismo di risoluzione pacchetto non è cambiato più di tanto tra 2 e 3.
Kevin

2
"se stai usando Python 3 non c'è più bisogno di __init__.pyfile." Al contrario, puoi descrivere le cose se vogliamo che un pacchetto funzioni sia in 2 che in 3? E guarda il 2009 tristemente obsoleto A cosa serve __init__.py? e la sua risposta più votata "Fa parte di un pacchetto" . Dobbiamo iniziare a enfatizzare la distinzione "pacchetto regolare [vecchio, pre-3.3]" vs "pacchetto spazio dei nomi [3.3+]" ovunque e spesso.
smci

61

L'avevo capito. Molto frustrante, soprattutto proveniente da python2.

Devi aggiungere .a al modulo, indipendentemente dal fatto che sia relativo o assoluto.

Ho creato la configurazione della directory come segue.

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

modx.py

def does_something():
    return "I gave you this string."

mody.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

quando eseguo main, questo è quello che succede

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

Ho eseguito 2to3 e l'output principale è stato questo

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

Ho dovuto modificare la dichiarazione di importazione di mody.py per risolverlo

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

Quindi ho eseguito nuovamente main.py e ho ottenuto l'output previsto

$ python main.py
I gave you this string.

Infine, solo per ripulirlo e renderlo portatile tra 2 e 3.

from __future__ import absolute_import
from .modx import does_something

1
Vale la pena notare che la try/exceptprocedura di caricamento è l'ingrediente reale che funziona qui (poiché alcune persone dovranno utilizzare try:scripts.modxe except: modx), ed è stato ciò che ha risolto questo problema per me.
Justapigeon

40

L'impostazione di PYTHONPATH può anche aiutare con questo problema.

Ecco come può essere fatto su Windows

set PYTHONPATH=.


11
l'impostazione di PYTHONPATH sulla directory del codice principale ha risolto il problema per me!
Geek,

1
Funziona anche in Linux. esportazione PYTHONPATH =.
rjdkolb,

29

Devi aggiungere il percorso del modulo a PYTHONPATH.


Per UNIX (Linux, OSX, ...)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

Per Windows

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\module\

4
Grazie enormi @Giorgos! Ciò è particolarmente vero quando si tenta di impostare una directory radice in un'immagine docker.
Tony Fraser,

15

Ho provato il tuo esempio

from . import config

ottenuto il seguente SystemError:
/usr/bin/python3.4 test.py
Traceback (ultima chiamata più recente):
File "test.py", riga 1, in
da. import config
SystemError: modulo genitore '' non caricato, impossibile eseguire l'importazione relativa


Questo funzionerà per me:

import config
print('debug=%s'%config.debug)

>>>debug=True

Testato con Python: 3.4.2 - PyCharm 2016.3.2


Oltre a questo PyCharm ti offre di importare questo nome .
Devi fare clic su confige appare un'icona di aiuto . inserisci qui la descrizione dell'immagine


11

È possibile semplicemente aggiungere il seguente file alla directory dei test, quindi Python lo eseguirà prima dei test

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

Questo è quello che stavo esattamente cercando. Grazie per aver condiviso questa risposta !!!
Mayur,

Fare qualcosa del genere genera un errore linter (pylint3). L'errore è simile a questo. nomefile.py:12:0: C0413: l'importazione "import abc.def.ghi.file_util come file_util" deve essere posizionata nella parte superiore del modulo (posizione di importazione errata)
Sharad

6

Imposta PYTHONPATHla variabile di ambiente nella directory di progetto principale.

Considerando UNIX-like:

export PYTHONPATH=.

4

Questo esempio funziona su Python 3.6.

Suggerisco di andare Run -> Edit Configurationsin PyCharm, eliminare eventuali voci lì e provare a eseguire nuovamente il codice tramite PyCharm.

Se il problema persiste, controlla l'interprete del progetto (Impostazioni -> Interprete del progetto) ed esegui le impostazioni predefinite di configurazione (Esegui -> Modifica configurazioni ...).


4

Dichiarare l' elenco sys.path corretto prima di chiamare il modulo:

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')

1

Come è stato affermato nei commenti al post originale, questo sembrava essere un problema con l'interprete Python che stavo usando per qualsiasi motivo e non qualcosa di sbagliato con gli script Python. Sono passato dal bundle WinPython al python 3.6 ufficiale di python.org e ha funzionato perfettamente. Grazie per l'aiuto a tutti :)


1
Hmm odio dirlo ma mi è appena successa la stessa cosa. La ricreazione dell'ambiente risolve il problema. Nel mio caso, ho riscontrato questo errore durante l'esecuzione dei test. Nello stesso ambiente, provare a importare lo stesso modulo funzionante. L'ambiente di ricreazione li ha riparati tutti (stessa versione di Python 3.6)
naoko

1
IDE diversi hanno un modo diverso di gestire i percorsi appositamente per i file di origine del progetto (viste, moduli, modelli, ecc.) Se il progetto è strutturato e codificato correttamente, dovrebbe funzionare con tutti gli IDE (standard). Avere problemi con IDE popolari come WinPython significa che il problema proviene effettivamente dal tuo progetto. Come accennato in precedenza, il problema è "Devi aggiungere un. Al modulo" dall'utente3159377 che dovrebbe essere la risposta accettata.
Linux,

1

Se stai usando Python 3+, prova ad aggiungere le righe seguenti

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)

0

Provare

from . import config

Quello che fa è importare dallo stesso livello di cartella. Se si tenta di importare direttamente, si presuppone che sia un subordinato

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.