ModuleNotFoundError: geen module met de naam ‘__main__.xxxx’; ‘__main__’ is geen pakket

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.py3de fout. Wat moet hier worden gewijzigd?


Antwoord 1, autoriteit 100%

.moduleBis een relatieve import. Relatief werkt alleen wanneer de bovenliggende module eerst wordt geïmporteerd of geladen. Dat betekent dat u projergens in uw huidige runtime-omgeving moet hebben geïmporteerd. Wanneer u het commando python3 moduleA.py3gebruikt, krijgt het geen kans om de bovenliggende module te importeren. Je kunt:

  • from proj.moduleB import moduleBOF
  • Je kunt een ander script maken, laten we zeggen run.py, om from 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.pyte 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.pyrechtstreeks 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.mainimporteren 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: commonis 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 commonmodule 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.pyeindigt 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.py3uitvoert, wordt moduleAgebruikt 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 importverwijderen, 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.

Other episodes