Comment faire par rapport importations en Python?
Imaginer cette structure de répertoire:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Je suis codage mod1
, et j'ai besoin d'importer quelque chose de mod2
. Comment dois-je faire?
J'ai essayé from ..sub2 import mod2
mais je suis une "Tentative relative à l'importation de non-package".
J'ai googlé autour mais n'a trouvé qu' "sys.path
la manipulation de" hacks. N'est-il pas un moyen propre?
Edit: toutes mes __init__.py
's sont actuellement vide
Edit2: je suis en train de le faire parce que sub2 contient des classes qui sont partagés entre les sous-paquetages (sub1
, subX
, etc.).
Edit3: Le comportement, je suis à la recherche est la même que celle décrite dans PEP 366 (merci John B)
- Je vous recommande de mettre à jour votre question pour le rendre plus clair que vous êtes en décrivant le problème traité dans le PEP 366.
- C'est un de longue haleine explications, mais regarde ici: stackoverflow.com/a/10713254/1267156 j'ai répondu à une question très semblable. J'ai eu ce même problème jusqu'à ce que la nuit dernière.
- Pour ceux qui veulent charger un module situé à l'arbitraire d'un chemin d'accès, voir ceci: stackoverflow.com/questions/67631/...
- Sur une note connexe, Python 3 va changer la gestion par défaut des importations être absolue par défaut; par rapport importations devra être spécifiée explicitement.
Vous devez vous connecter pour publier un commentaire.
Tout le monde semble vouloir de vous dire ce que vous devriez faire plutôt que de simplement répondre à la question.
Le problème est que vous utilisez le module '__principaux__' en passant par le mod1.py comme un argument à l'interprète.
De PEP 328:
En Python 2.6, ils sont en ajoutant la possibilité de référence des modules par rapport au module principal. PEP 366 décrit le changement.
Mise à jour: Selon Nick Coghlan, l'option recommandée est de lancer le module à l'intérieur de l'emballage, en utilisant le commutateur-m.
-m
commutateur, plutôt que d'en spécifiant leur nom de fichier directement.from sub2 import mod2
. Ensuite, pour exécuter mod1, à partir de l'intérieur de l'app, nepython -m sub1.mod1
.python -m app.sub1.mod1
(de la mère dir deapp
) comme Pankaj a écrit.from .m import whatever
dans un script que vous passez un argument d'interprète, qu'il est fondamentalement résout pourfrom __main__.m import whatever
. Qui lui donne une apparence pour__main__/m.py
.python main.py
.main.py
n':import app.package_a.module_a
module_a.py
neimport app.package_b.module_b
Sinon 2 ou 3 peut utiliser:
from app.package_a import module_a
Qui va travailler aussi longtemps que vous avez
app
dans votre PYTHONPATH.main.py
pourrait être n'importe où ensuite.Si vous écrivez un
setup.py
à copier (à installer), l'ensemble du package de l'application et des sous-paquets à l'objectif du système de python dossiers, etmain.py
à la cible du système de script dossiers.Voici la solution qui fonctionne pour moi:
Je ne la relative des importations de l'
from ..sub2 import mod2
et puis, si je veux courir
mod1.py
puis-je aller vers le répertoire parent duapp
et exécuter le module à l'aide de python-m interrupteur depython -m app.sub1.mod1
.La vraie raison pour laquelle ce problème se produit avec une relative des importations, c'est que relative des importations fonctionne en prenant la
__name__
propriété du module. Si le module est directement exécuté, puis__name__
est fixé à__main__
et qu'il ne contient aucune information sur la structure du package. Et, c'est pourquoi python se plaint de larelative import in non-package
erreur.Ainsi, en utilisant le commutateur-m vous offrir le paquet d'informations de structure de python, à travers lequel il est possible de résoudre la relative des importations avec succès.
J'ai rencontré ce problème plusieurs fois tout en faisant relative des importations. Et, après la lecture de toutes les réponses précédentes, je n'étais pas encore en mesure de comprendre comment le résoudre, de façon propre, sans avoir besoin de mettre le code réutilisable dans tous les fichiers. (Bien que certains commentaires étaient vraiment utile, merci à @ncoghlan et @XiongChiamiov)
Espère que cela aide quelqu'un qui se bat avec une relative des importations de problème, car en passant par le PEP est vraiment pas amusant.
-m
a été conçu pour les résoudre.from . import some_module
."Guido vue sur l'exécution de scripts à l'intérieur d'un package comme un anti-pattern" (rejetée
PEP-3122)
J'ai passé tellement de temps à essayer de trouver une solution, la lecture related posts ici sur Stack Overflow, et en me disant: "il doit y avoir une meilleure façon!". Regarde comme il n'est pas.
-m
commutateur:python -m app.sub1.mod1
ou invoquerapp.sub1.mod1.main()
à partir d'un script de niveau supérieur (par exemple, généré à partir de setuptools' entry_points définis dans setup.py).Cela est résolu à 100%:
Importation settings/local_setting.py dans app/main.py:
main.py:
sys.path.insert(0, "../settings")
et puisfrom local_settings import *
Je suis à l'aide de cet extrait de code pour importer des modules de chemins, de l'espoir qui aide
explication de
nosklo's
réponse avec des exemplesnote: tous les
__init__.py
fichiers sont vides.app/package_a/fun_a.py
app/package_b/fun_b.py
main.py
si vous exécutez
$ python main.py
il retourne:from app.package_b import fun_b
from app.package_a.fun_a import print_a
donc fichier dans le dossier
package_b
utilisé le fichier dans le dossierpackage_a
, qui est ce que vous voulez. Le droit??C'est malheureusement un sys.chemin de hack, mais il fonctionne très bien.
J'ai rencontré ce problème avec une autre couche: j'ai déjà eu un module du nom spécifié, mais c'était le mauvais module.
ce que je voulais faire était la suivante (le module je travaillais était module3):
Remarque que j'ai déjà installé mymodule, mais dans mon installation, je n'ai pas "mymodule1"
et je voudrais obtenir une ImportError parce qu'il essayait de les importer à partir de mes modules installés.
J'ai essayé de faire un sys.chemin d'accès.ajouter, et cela ne fonctionne pas. Ce n'est un sys.chemin d'accès.insérez
Donc une sorte de hack, mais j'ai tout de travailler!
Donc, gardez à l'esprit, si vous voulez que votre décision de l'emporter sur d'autres chemins alors vous devez utiliser sys.chemin d'accès.insert(0, chemin d'accès) pour qu'il fonctionne! C'était très frustrant point d'achoppement pour moi, beaucoup de gens disent d'utiliser la fonction "append" pour sys.chemin d'accès, mais qui ne fonctionne pas si vous avez déjà un module défini (je trouve ça très étrange comportement)
sys.path.append('../')
fonctionne très bien pour moi (Python 3.5.2)Permettez-moi juste de mettre cette question ici de ma propre référence. Je sais que c'est pas bon du code Python, mais j'ai besoin d'un script pour un projet sur lequel je travaillais et je voulais mettre le script dans un
scripts
répertoire.Comme @EvgeniSergeev dit dans les commentaires de l'OP, vous pouvez importer le code à partir d'un
.py
fichier à un emplacement arbitraire avec:Ceci est pris à partir de cette SORTE de réponse.
Prendre un coup d'oeil à http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports. Vous pourriez faire
De Python doc,
J'ai trouvé c'est plus facile à mettre en "PYTHONPATH" environnement variable à haut dossier:
alors:
bien sûr, PYTHONPATH est "global", mais il ne soulève pas de problèmes pour moi encore.
virtualenv
vous permet de gérer vos déclarations d'importation.Sur le dessus de ce que John B dit, il semble que le réglage de la
__package__
variable devrait aider, au lieu de changer__main__
qui pourraient vis d'autres choses. Mais autant que j'ai pu tester, il n'est pas complètement le travail comme il se doit.J'ai le même problème et ni PEP 328 ou 366 résoudre complètement le problème, car les deux, d'ici à la fin de la journée, besoin de la tête de l'emballage pour être inclus dans
sys.path
, aussi loin que je pouvais comprendre.Je dois aussi mentionner que je n'ai pas trouver comment le format de la chaîne qui doit aller à ces variables. Est-il
"package_head.subfolder.module_name"
ou quoi?Supposons que vous exécutez au niveau supérieur, puis dans
mod1
utilisation:au lieu de