Imaginez cette structure de répertoire:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Je suis en train de coder mod1
et j'ai besoin d'importer quelque chose mod2
. Comment dois-je procéder?
J'ai essayé from ..sub2 import mod2
mais j'obtiens une «tentative d'importation relative dans un non-package».
Je suis allé sur Google, mais je n'ai trouvé que sys.path
des hacks de " manipulation". N'y a-t-il pas une voie propre?
Edit: tous les mes __init__.py
sont actuellement vides
Edit2: Je suis en train de le faire parce que SUB2 contient des classes qui sont partagées entre les sous répertoires ( sub1
, subX
, etc.).
Edit3: Le comportement que je recherche est le même que celui décrit dans PEP 366 (merci John B)
Réponses:
Tout le monde semble vouloir vous dire ce que vous devriez faire plutôt que de simplement répondre à la question.
Le problème est que vous exécutez le module en tant que '__main__' en passant le mod1.py comme argument à l'interpréteur.
Depuis PEP 328 :
Dans Python 2.6, ils ajoutent la possibilité de référencer des modules par rapport au module principal. Le PEP 366 décrit le changement.
Mise à jour : Selon Nick Coghlan, l'alternative recommandée consiste à exécuter le module à l'intérieur du package à l'aide du commutateur -m.
la source
-m
commutateur, plutôt qu'en spécifiant directement leur nom de fichier.from sub2 import mod2
. Ensuite, pour exécuter mod1, à partir de l'application, faitespython -m sub1.mod1
.Voici la solution qui me convient:
Je fais les importations relatives en tant
from ..sub2 import mod2
que puis, si je veux exécuter,mod1.py
je vais dans le répertoire parent deapp
et exécute le module en utilisant le commutateur python -m aspython -m app.sub1.mod1
.La vraie raison pour laquelle ce problème se produit avec les importations relatives est que les importations relatives fonctionnent en prenant la
__name__
propriété du module. Si le module est exécuté directement, il__name__
est défini sur__main__
et ne contient aucune information sur la structure du package. Et, c'est pourquoi python se plaint de l'relative import in non-package
erreur.Ainsi, en utilisant le commutateur -m, vous fournissez les informations de structure de package à python, grâce auxquelles il peut résoudre les importations relatives avec succès.
J'ai rencontré ce problème plusieurs fois lors d'importations relatives. Et, après avoir lu toutes les réponses précédentes, je n'arrivais toujours pas à comprendre comment le résoudre, d'une manière propre, sans avoir besoin de mettre du code passe-partout dans tous les fichiers. (Bien que certains des commentaires aient été très utiles, merci à @ncoghlan et @XiongChiamiov)
J'espère que cela aide quelqu'un qui se bat avec un problème d'importations relatives, car passer par le PEP n'est vraiment pas amusant.
la source
-m
été conçu pour résoudre.from . import some_module
.python main.py
.main.py
Est-ce que:import app.package_a.module_a
module_a.py
Est-ce queimport app.package_b.module_b
Alternativement, 2 ou 3 pourraient utiliser:
from app.package_a import module_a
Cela fonctionnera aussi longtemps que vous en aurez
app
dans votre PYTHONPATH.main.py
pourrait être n'importe où alors.Vous écrivez donc un
setup.py
pour copier (installer) l'ensemble du package et des sous-packages de l'application dans les dossiers python du système cible etmain.py
dans les dossiers de script du système cible.la source
"Guido considère l'exécution de scripts dans un package comme un anti-modèle" (rejeté PEP-3122 )
J'ai passé tellement de temps à essayer de trouver une solution, à lire les articles liés ici sur Stack Overflow et à me dire "il doit y avoir une meilleure façon!". On dirait qu'il n'y en a pas.
la source
-m
switch:python -m app.sub1.mod1
ou invoquer àapp.sub1.mod1.main()
partir d'un script de niveau supérieur (par exemple, généré à partir des points d'entrée de setuptools définis dans setup.py).Ceci est résolu à 100%:
Importez les paramètres / local_setting.py dans l'application / main.py:
main.py:
la source
sys.path.insert(0, "../settings")
, puisfrom local_settings import *
J'utilise cet extrait pour importer des modules à partir de chemins, j'espère que cela aide
la source
explication de la
nosklo's
réponse avec des exemplesremarque: tous les
__init__.py
fichiers sont vides.app / package_a / fun_a.py
app / package_b / fun_b.py
main.py
si vous l'exécutez,
$ python main.py
il renvoie:from app.package_b import fun_b
from app.package_a.fun_a import print_a
donc fichier dans le dossier
package_b
utilisé fichier dans le dossierpackage_a
, ce que vous voulez. Droite??la source
Il s'agit malheureusement d'un hack sys.path, mais cela fonctionne assez bien.
J'ai rencontré ce problème avec une autre couche: j'avais déjà un module du nom spécifié, mais ce n'était pas le bon module.
ce que je voulais faire était le suivant (le module à partir duquel je travaillais était module3):
Notez que j'ai déjà installé mymodule, mais dans mon installation je n'ai pas "mymodule1"
et j'obtiendrais un ImportError car il essayait d'importer à partir de mes modules installés.
J'ai essayé de faire un sys.path.append, et cela n'a pas fonctionné. Ce qui a fonctionné était un sys.path.insert
Donc, une sorte de hack, mais tout a fonctionné! Alors gardez à l'esprit, si vous voulez que votre décision écrase d'autres chemins, vous devez utiliser sys.path.insert (0, chemin d'accès) pour le faire fonctionner! C'était un point de friction très frustrant pour moi, beaucoup de gens disent d'utiliser la fonction "append" dans sys.path, mais cela ne fonctionne pas si vous avez déjà un module défini (je trouve cela très étrange)
la source
sys.path.append('../')
fonctionne bien pour moi (Python 3.5.2)Permettez-moi de mettre ceci ici pour ma propre référence. Je sais que ce n'est pas du bon code Python, mais j'avais besoin d'un script pour un projet sur lequel je travaillais et je voulais mettre le script dans un
scripts
répertoire.la source
Comme @EvgeniSergeev le dit dans les commentaires de l'OP, vous pouvez importer du code à partir d'un
.py
fichier à un emplacement arbitraire avec:Ceci est tiré de cette réponse SO .
la source
Jetez un œil à http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . Vous pourriez faire
la source
De doc Python ,
la source
J'ai trouvé qu'il était plus facile de définir la variable d'environnement "PYTHONPATH" dans le dossier supérieur:
puis:
bien sûr, PYTHONPATH est "global", mais cela ne m'a pas encore posé de problème.
la source
virtualenv
vous pouvez gérer vos instructions d'importation.En plus de ce que John B a dit, il semble que la définition de la
__package__
variable devrait aider, au lieu de changer__main__
ce qui pourrait gâcher d'autres choses. Mais pour autant que je puisse tester, cela ne fonctionne pas complètement comme il se doit.J'ai le même problème et aucun PEP 328 ou 366 ne résout le problème complètement, car les deux, à la fin de la journée, ont besoin que la tête du paquet soit incluse
sys.path
, pour autant que je puisse comprendre.Je dois également mentionner que je n'ai pas trouvé comment formater la chaîne qui devrait aller dans ces variables. C'est
"package_head.subfolder.module_name"
ou quoi?la source
Vous devez ajouter le chemin du module à
PYTHONPATH
:la source
sys.path
, car ellesys.path
est initialisée à partir dePYTHONPATH
sys.path
doit être codé en dur dans le code source contrairement àPYTHONPATH
ce qui est une variable d'environnement et peut être exporté.