Ik heb een python-project (dat ik binnen een virtualenv uitvoer) en dat heeft de volgende structuur:
Project
├───.git
├───venv
└───src
├───__init__.py
├───mymodules
│ ├───__init__.py
│ ├───module1.py
│ └───module2.py
└───scripts
├───__init__.py
└───script.py
script.py
import src.mymodules.module1
...
Ik voer het project uit met venv geactiveerd en vanuit de map Project met het volgende commando:
(venv)$ python src/scripts/script.py
Het script wordt uitgevoerd, maar geeft de volgende foutmelding voordat het wordt afgesloten:
Traceback (most recent call last):
File "src/scripts/script.py", line 1, in <module>
import src.mymodules.module1
ImportError: No module named src.mymodules.module1
Ik heb geprobeerd de python-shell uit te voeren en de module van daaruit te importeren en het gaf geen fouten. Ik heb _ _init__.py in elke map binnen src. Overweegt python de werkdirectory als src/scripts? Waarom gebeurt dat en hoe kan ik src de werkdirectory maken als dat het geval is?
Antwoord 1, autoriteit 100%
In wezen, wanneer u script.py
rechtstreeks uitvoert, weet het niet dat het deel uitmaakt van een submodule van src
, en ook niet waar een module met de naam src
zou kunnen zijn. Dit is het geval in python 2 of 3.
Zoals u weet, vindt Python modules op basis van de inhoud van sys.path
. Om een module te kunnen importeren, moet deze zich ofwel in een map bevinden die wordt vermeld in sys.path
, of in dezelfde map als het script dat u uitvoert.
Als je python src/scripts/script.py
zegt, bevat sys.path
het Project/src/scripts/
(omdat dat waar script.py
zich bevindt), maar niet Project
. Omdat Project
niet in het pad staat, kunnen de modules in die map (src
) niet worden geïmporteerd.
Om dit op te lossen:
Ik neem aan dat uw script.py
een toegangspunt is voor uw src
-module (misschien is dit bijvoorbeeld het hoofdprogramma). Als dat waar is, kun je het oplossen door script.py
naar hetzelfde niveau te verplaatsen als src
:
Project
├───.git
├───venv
|───script.py <--- script.py moves up here
└───src
├───__init__.py
└───mymodules
├───__init__.py
├───module1.py
└───module2.py
Op deze manier kan script.py
alles vrij importeren in src
, maar niets in src
kan script.py
.
Als dat niet het geval is, en script.py
echt een onderdeel is van src
, kun je -m
argument om script.py
uit te voeren als onderdeel van de src
module als volgt:
$ python -m src.scripts.script
Omdat je python hebt verteld welke module je gebruikt (src
), zal het in het pad staan. Dus script.py
weet dat het een submodule is van src
, en kan dan importeren vanuit src
.
Wees echter voorzichtig in deze situatie – het is mogelijk om een circulaire import te maken als iets in src
src.scripts.script
importeert.
Als alternatief voor beide benaderingen kunt u het sys.path
rechtstreeks in script.py
wijzigen:
import sys
sys.path.insert(0, '/path/to/Project') # location of src
Hoewel dit werkt, heeft het meestal niet mijn voorkeur. Het vereist script.py
om precies te weten hoe je code is ingedeeld, en kan importverwarring veroorzaken als een ander python-programma ooit probeert script.py
te importeren.
Antwoord 2, autoriteit 4%
Als u met dit probleem wordt geconfronteerd bij het omgaan met Pytest
of coverage
. Het toevoegen van het bestand __init__.py
lost de meeste gevallen op.
Antwoord 3, autoriteit 2%
Project
├───.git
├───venv
└───src
├───__init__.py
├───mymodules
│ ├───__init__.py
│ ├───module1.py
│ └───module2.py
└───scripts
├───__init__.py
└───script.py
U kunt ook als volgt importeren in uw script.py
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__),'../../'))
import src.mymodules.module1
Nu kunt u het script.py-bestand vanaf elke locatie uitvoeren.
e.g :
python script.py
python /path to folder/script.py
Antwoord 4
Een andere oplossing is het aanmaken van de bestandsnaam ‘xxx(any name).pth’ en het schrijven van je projectmap (moedermap van je src). Zet dit bestand in ‘/virtual_env/lib/pythonXX/site-packages/’. Op deze manier hoeft u sys.path niet in uw script te importeren.