Ik probeer momenteel in Python3 te werken en absolute imports te gebruiken om de ene module in de andere te importeren, maar ik krijg de fout ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package
. Overweeg deze projectstructuur:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
Dan geeft het uitvoeren van python3 moduleA.py3
de fout. Wat moet hier worden gewijzigd?
Antwoord 1, autoriteit 100%
.moduleB
is een relatieve import. Relatief werkt alleen wanneer de bovenliggende module eerst wordt geïmporteerd of geladen. Dat betekent dat u proj
ergens in uw huidige runtime-omgeving moet hebben geïmporteerd. Wanneer u het commando python3 moduleA.py3
gebruikt, krijgt het geen kans om de bovenliggende module te importeren. Je kunt:
from proj.moduleB import moduleB
OF- Je kunt een ander script maken, laten we zeggen
run.py
, omfrom proj import moduleA
op te roepen
Veel succes met je reis naar het geweldige land Python.
Antwoord 2, autoriteit 71%
Voorwoord
Ik ben een project aan het ontwikkelen dat in feite een Python-pakket is dat kan worden geïnstalleerd via pip, maar het geeft ook toegang tot een opdrachtregelinterface. Ik heb geen problemen met het uitvoeren van mijn project nadat ik het heb geïnstalleerd met pip install .
, maar ja, wie doet dit elke keer nadat er iets in een van de projectbestanden is gewijzigd? Ik moest het hele ding door middel van eenvoudige python mypackage/main.py
.
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
De verschillende gezichten van hetzelfde probleem
Ik heb geprobeerd een paar functies in main.py
te importeren vanuit mijn common.py
-module. Ik heb verschillende configuraties geprobeerd die verschillende fouten gaven, en ik wil mijn observaties met u delen en ook een korte notitie achterlaten voor toekomstige mij.
Relatieve import
Het eerste wat ik probeerde was een relatieve import:
from .common import my_func
Ik heb mijn applicatie uitgevoerd met eenvoudig: python mypackage/main.py
. Helaas gaf dit de volgende foutmelding:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
De oorzaak van dit probleem is dat de main.py
rechtstreeks werd uitgevoerd door de opdracht python
, waardoor het de hoofdmodule werd met de naam __main__
. Als we deze informatie koppelen aan de relatieve import die we hebben gebruikt, krijgen we wat we hebben in de foutmelding: __main__.common
. Dit wordt uitgelegd in de Python-documentatie:
Houd er rekening mee dat relatieve importen zijn gebaseerd op de naam van de huidige module. Aangezien de naam van de hoofdmodule altijd
__main__
is, moeten modules die bedoeld zijn voor gebruik als de hoofdmodule van een Python-toepassing altijd absolute import gebruiken.
Toen ik mijn pakket installeerde met pip install .
en het vervolgens uitvoerde, werkte het prima. Ik kon ook de module mypackage.main
importeren in een Python-console. Het lijkt er dus op dat er alleen een probleem is met het rechtstreeks uitvoeren ervan.
Absolute import
Laten we het advies uit de documentatie opvolgen en de importverklaring wijzigen in iets anders:
from common import my_func
Als we dit nu proberen uit te voeren zoals eerder: python mypackage/main.py
, dan werkt het zoals verwacht! Maar er is een waarschuwing wanneer u, net als ik, iets ontwikkelt dat moet werken als een standalone opdrachtregelprogramma nadat u het met piphebt geïnstalleerd. Ik installeerde mijn pakket met pip install .
en probeerde het vervolgens uit te voeren…
ModuleNotFoundError: No module named 'common'
Erger nog, toen ik een Python-console opende en probeerde de main
-module handmatig te importeren (import mypackage.main
), kreeg ik dezelfde foutmelding als hierboven . De reden daarvoor is simpel: common
is niet langer een relatieve import, dus Python probeert het te vinden in geïnstalleerde pakketten. We hebben zo’n pakket niet, daarom mislukt het.
De oplossing met een absolute import werkt alleen goed als je een typische Python-app maakt die wordt uitgevoerd met een python
-opdracht.
Importeren met een pakketnaam
Er is ook een derde mogelijkheid om de common
module te importeren:
from mypackage.common import my_func
Dit verschilt niet veel van de relatieve import-aanpak, zolang we het maar doen vanuit de context van mypackage
. En nogmaals, proberen om dit uit te voeren met python mypackage/main.py
eindigt vergelijkbaar:
ModuleNotFoundError: No module named 'mypackage'
Hoe irritant dat ook kan zijn, de tolk heeft gelijk, je hebt zo’n pakket niet geïnstalleerd.
De oplossing
Voor eenvoudige Python-apps
Gebruik gewoon absolute import (zonder de punt), en alles komt goed.
Voor installeerbare Python-apps in ontwikkeling
Gebruik relatieve imports, of imports met een pakketnaam aan het begin, omdat je ze zo nodig hebt wanneer je app is geïnstalleerd. Als het gaat om het uitvoeren van een dergelijke module in ontwikkeling, kan Python worden uitgevoerd met de optie -m
:
-m mod : run library module as a script (terminates option list)
Dus in plaats van python mypackage/main.py
, doe het als volgt: python -m mypackage.main
.
Antwoord 3, autoriteit 51%
Naast het antwoord van md-sabuj-sarker is er een heel goed voorbeeld in de Documentatie over Python-modules.
Dit is wat de documenten zeggen over intra-package-references :
Houd er rekening mee dat relatieve importen zijn gebaseerd op de naam van de huidige module. Aangezien de naam van de hoofdmodule altijd
"__main__"
is, moeten modules die bedoeld zijn voor gebruik als de hoofdmodule van een Python-toepassing altijd absolute import gebruiken.
Als je python3 moduleA.py3
uitvoert, wordt moduleA
gebruikt als de hoofdmodule, dus het lijkt de juiste keuze om de absolute import te gebruiken.
Pas echter op dat deze absolute import (from package.module import something
) mislukt als, om wat voor reden dan ook, het pakket een modulebestand bevat met dezelfde naam als het pakket (tenminste, op mijn Python 3.7). Het zou dus mislukken als je (naar het voorbeeld van de OP):
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
in dat geval krijgt u:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
U kunt ook de .
in from .moduleB import
verwijderen, zoals voorgesteld hieren hier, wat lijkt te werken, hoewel mijn PyCharm (2018.2.4) dit markeert als een “Onopgeloste referentie ” en kan niet automatisch worden aangevuld.
Antwoord 4, autoriteit 6%
Misschien kunt u dit doen voordat u de module importeert:
moduleA.py3
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
Voeg de huidige map toe aan de omgevingsmap
Antwoord 5
Hernoem het bestand van waaruit u de app uitvoert naar main.py:
from app import app
if __name__ == '__main__':
app.run()
Antwoord 6
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
zal het probleem met het importpad oplossen.