Ik heb allerlei voorbeelden en andere soortgelijke vragen gezien, maar ik kan geen voorbeeld vinden dat precies overeenkomt met mijn scenario. Ik voel me een totale idioot om dit te vragen omdat er zoveel soortgelijke vragen zijn, maar ik krijg dit gewoon niet “goed” werkend. Hier is mijn project:
user_management (package)
|
|------- __init__.py
|
|------- Modules/
| |
| |----- __init__.py
| |----- LDAPManager.py
| |----- PasswordManager.py
|
|------- Scripts/
| |
| |----- __init__.py
| |----- CreateUser.py
| |----- FindUser.py
Als ik “CreateUser.py” naar de hoofddirectory user_management verplaats, kan ik gemakkelijk: "import Modules.LDAPManager"
gebruiken om LDAPManager.py te importeren — dit werkt. Wat ik niet kan doen (wat ik wil doen), is CreateUser.py in de submap Scripts houden en LDAPManager.py importeren. Ik hoopte dit te bereiken door "import user_management.Modules.LDAPManager.py"
te gebruiken. Dit werkt niet. Kortom, ik kan Python-bestanden gemakkelijk dieper in de hiërarchie laten kijken, maar ik kan geen Python-script krijgen om naar de ene map en naar de andere te verwijzen.
Merk op dat ik mijn probleem kan oplossen met:
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import Modules.LDAPManager as LDAPManager
Ik heb gehoord dat dit een slechte gewoonte is en wordt afgeraden.
De bestanden in Scripts zijn bedoeld om direct te worden uitgevoerd (is de init.py in Scripts zelfs nodig?). Ik heb gelezen dat ik in dit geval CreateUser.py zou moeten uitvoeren met de vlag -m. Ik heb hier wat variaties op geprobeerd en het lijkt erop dat CreateUser.py LDAPManager.py niet herkent.
Antwoord 1, autoriteit 100%
Als ik
CreateUser.py
naar de hoofddirectory user_management verplaats, kan ik
gebruik eenvoudig:import Modules.LDAPManager
omLDAPManager.py
te importeren
— dit werkt.
Alsjeblieft, niet doen. Op deze manier zal de LDAPManager
-module die wordt gebruikt door CreateUser
nietdezelfde zijn als de module die via andere imports is geïmporteerd. Dit kan problemen opleveren wanneer u een globale toestand in de module heeft of tijdens het beitsen/ontbeitsen. Vermijdimports die alleen werken omdat de module zich in dezelfde directory bevindt.
Als u een pakketstructuur heeft, moet u:
-
Gebruik relatieve import, d.w.z. als de
CreateUser.py
inScripts/
staat:from ..Modules import LDAPManager
Merk op dat dit werd(let op de verledentijd) ontmoedigd door PEP 8alleen omdat oude versies van python ze niet zo goed ondersteunden, maar dit probleem was jaren geleden opgelost. De huidigeversie van PEP 8 suggereertze als een acceptabel alternatief voor absolute import. Ik vind ze leukin pakketten.
-
Gebruik absolute import met de hele pakketnaam(
CreateUser.py
inScripts/
):from user_management.Modules import LDAPManager
Om de tweede te laten werken, moet het pakket user_management
binnen het PYTHONPATH
worden geïnstalleerd. Tijdens de ontwikkeling kunt u de IDE zo configureren dat dit gebeurt, zonder dat u ergens handmatig aanroepen hoeft toe te voegen aan sys.path.append
.
Ik vind het ook vreemd dat Scripts/
een subpakket is. Omdat in een echte installatie de module user_management
zou worden geïnstalleerd onder de site-packages
in de directory lib/
(welke directory ook wordt gebruikt om bibliotheken in uw besturingssysteem), terwijl de scripts moeten worden geïnstalleerd onder een bin/
-directory (afhankelijk van welke uitvoerbare bestanden voor uw besturingssysteem bevatten).
In feite geloof ik dat Script/
niet eens onder user_management
zou moeten staan. Het moet zich op hetzelfde niveau van user_management
bevinden.
Op deze manier hoef je niet-m
te gebruiken, maar je moet er alleen voor zorgen dat het pakket gevonden kan worden (ook dit is een kwestie van de IDE configureren, installeren het pakket correct of door PYTHONPATH=. python Scripts/CreateUser.py
te gebruiken om de scripts met het juiste pad te starten).
Samengevat is de hiërarchie die ikzou gebruiken:
user_management (package)
|
|------- __init__.py
|
|------- Modules/
| |
| |----- __init__.py
| |----- LDAPManager.py
| |----- PasswordManager.py
|
Scripts/ (*not* a package)
|
|----- CreateUser.py
|----- FindUser.py
Vervolgens moet de code van CreateUser.py
en FindUser.py
absolute imports gebruiken om de modules te importeren:
from user_management.Modules import LDAPManager
Tijdens de installatie zorg je ervoor dat user_management
ergens in de PYTHONPATH
terechtkomt, en de scripts in de directory voor uitvoerbare bestanden zodat ze de modules kunnen vinden. Tijdens de ontwikkeling vertrouw je ofwel op de IDE-configuratie, of je start CreateUser.py
en voegt de bovenliggende directory Scripts/
toe aan de PYTHONPATH
(ik bedoel de directory dat zowel user_management
als scripts
bevat):
PYTHONPATH=/the/parent/directory python Scripts/CreateUser.py
Of je kunt het PYTHONPATH
globaal wijzigen, zodat je dit niet elke keer hoeft op te geven. Op unix-besturingssystemen (linux, Mac OS X enz.) kunt u een van de shellscripts wijzigen om de externe variabele PYTHONPATH
te definiëren, op Windows moet u de instellingen voor omgevingsvariabelen wijzigen.
AddendumIk geloof dat als je python2 gebruikt, het beter is om ervoor te zorgen dat je impliciete relatieve invoer vermijdt door te zetten:
from __future__ import absolute_import
bovenaan je modules. Op deze manier betekent import X
altijdhet importeren van de toplevelmodule X
en zal nooit proberen de X.py
-bestand dat zich in dezelfde map bevindt (als die map niet in het PYTHONPATH
staat). Op deze manier is de enigemanier om een relatieve import uit te voeren het gebruik van de explicietesyntaxis (de from . import X
), wat beter is ( expliciet is beter dan impliciet).
Dit zorgt ervoor dat u nooit de “nep” impliciete relatieve imports gebruikt, aangezien deze een ImportError
zouden opleveren die duidelijk aangeeft dat er iets mis is. Anders zou je een module kunnen gebruiken die niet is wat je denkt dat het is.
Antwoord 2, autoriteit 20%
Vanaf Python 2.5 kunt u
. gebruiken
from ..Modules import LDAPManager
De leidende periode brengt je een niveau omhoog in je hiërarchie.
Bekijk de Python-documenten op intra-package-referentiesvoor import.
Antwoord 3, autoriteit 7%
In de “root” __init__.py
kun je ook een
import sys
sys.path.insert(1, '.')
wat beide modules importeerbaar zou moeten maken.
Antwoord 4
Ik had dezelfde problemen. Om dit op te lossen heb ik export PYTHONPATH="$PWD"
gebruikt. In dit geval moet u echter de invoer in uw scripts
-map aanpassen, afhankelijk van het onderstaande:
Geval 1: Als u zich in de map user_management
bevindt, moeten uw scripts
deze stijl gebruiken from Modules import LDAPManager
om module te importeren.
Geval 2: Als u zich buiten het user_management
1-niveau bevindt, zoals main
, moeten uw scripts
deze stijl gebruiken from user_management.Modules import LDAPManager
om modules te importeren.